I'm fairly new to Rust so I came across this piece of code in the official Guide
let input = io::stdin().read_line()
.ok()
.expect("Failed to read line");
let input_num: Option<uint> = from_str(input.as_slice());
let num = match input_num {
Some(num) => num,
None => {
println!("Please input a number!");
return;
}
};
While the understand the first two statements (on input and inputnum), I'm not quite sure about the match statement. So I checked the documentation which shows that Option<T> can take two values , either None or Some(T) for some (object?) T. So I tested the following code:
io::println(
match input_num {
Some(num) => "somenum",
None => {
println!("Please input a number only!");
return;
}
}
);
This code works as expected; it prints somenum if you enter a number and otherwise it prints the error message. However, the compiler gives a warning stating: warning: unused variable:num, #[warn(unused_variable)] on by default. This confirmed my suspicions that the num inside the `match is used as a variable.
Question: How is it possible that rust does not complain about (in the Guide's example) having two variables with the same name num? Or does it "hand over" the pointer to the inside num to the outside num?
Also in the case of an empty return what exactly is returned? I'm guessing it is unit () because it is mentioned here that
functions without a -> ... implicitly have return type ()
Edit: Sorry for missing the obvious point. The return directly exits the function without bothering to put anything into num.
P.S. I noticed that using cargo build to compile does not give warnings the second time around (not making any changes). Does cargo keep tracking of versions or something?
Do you have any experiences with Java or C#? Many mainstream programing languages allows you to shadow a variable with another variable with the same name in a new block scope. For example, take a look at this C# code:
using System;
public class Test
{
public static void Main()
{
int x = 10;
{
int x = 20;
Console.WriteLine(x);
}
Console.WriteLine(x);
}
}
http://ideone.com/OuMlc8
In fact Rust is more flexible in terms of shadowing: you can shadow variables as many times as you want without explicitly making a brace block.
fn main() {
let i = 10i32;
let i = "foo";
println!("{}", i);
}
http://is.gd/CUHUOL
Here, the first i and the second i have no relationships. We just lose a way to use (refer to) the first i.
This confirmed my suspicions that the num inside the `match is used as a variable.
Yes, pattern matching can introduce new variables. But the new variable num introduced by pattern matching has no direct relationship with the outer num whose value is being given by the match expression.
I can translate your Rust code into less idiomatic Rust to illustrate what was happening:
let num =
if input_num.is_some() {
let num = input_num.unwrap();
num
} else {
println!("Please input a number!");
return;
}
;
As for not observing warnings from cargo build, I suspect it was because Cargo had already built .o from your code and didn't bother to repeat the same job twice, knowing that there was no change in your code.
Related
I noticed that Rust does not have exceptions. How to do error handling in Rust and what are the common pitfalls? Are there ways to control flow with raise, catch, reraise and other stuff? I found inconsistent information on this.
Rust generally solves errors in two ways:
Unrecoverable errors. Once you panic!, that's it. Your program or thread aborts because it encounters something it can't solve and its invariants have been violated. E.g. if you find invalid sequences in what should be a UTF-8 string.
Recoverable errors. Also called failures in some documentation. Instead of panicking, you emit a Option<T> or Result<T, E>. In these cases, you have a choice between a valid value Some(T)/Ok(T) respectively or an invalid value None/Error(E). Generally None serves as a null replacement, showing that the value is missing.
Now comes the hard part. Application.
Unwrap
Sometimes dealing with an Option is a pain in the neck, and you are almost guaranteed to get a value and not an error.
In those cases it's perfectly fine to use unwrap. unwrap turns Some(e) and Ok(e) into e, otherwise it panics. Unwrap is a tool to turn your recoverable errors into unrecoverable.
if x.is_some() {
y = x.unwrap(); // perfectly safe, you just checked x is Some
}
Inside the if-block it's perfectly fine to unwrap since it should never panic because we've already checked that it is Some with x.is_some().
If you're writing a library, using unwrap is discouraged because when it panics the user cannot handle the error. Additionally, a future update may change the invariant. Imagine if the example above had if x.is_some() || always_return_true(). The invariant would changed, and unwrap could panic.
? operator / try! macro
What's the ? operator or the try! macro? A short explanation is that it either returns the value inside an Ok() or prematurely returns error.
Here is a simplified definition of what the operator or macro expand to:
macro_rules! try {
($e:expr) => (match $e {
Ok(val) => val,
Err(err) => return Err(err),
});
}
If you use it like this:
let x = File::create("my_file.txt")?;
let x = try!(File::create("my_file.txt"));
It will convert it into this:
let x = match File::create("my_file.txt") {
Ok(val) => val,
Err(err) => return Err(err),
};
The downside is that your functions now return Result.
Combinators
Option and Result have some convenience methods that allow chaining and dealing with errors in an understandable manner. Methods like and, and_then, or, or_else, ok_or, map_err, etc.
For example, you could have a default value in case your value is botched.
let x: Option<i32> = None;
let guaranteed_value = x.or(Some(3)); //it's Some(3)
Or if you want to turn your Option into a Result.
let x = Some("foo");
assert_eq!(x.ok_or("No value found"), Ok("foo"));
let x: Option<&str> = None;
assert_eq!(x.ok_or("No value found"), Err("No value found"));
This is just a brief skim of things you can do. For more explanation, check out:
http://blog.burntsushi.net/rust-error-handling/
https://doc.rust-lang.org/book/ch09-00-error-handling.html
http://lucumr.pocoo.org/2014/10/16/on-error-handling/
If you need to terminate some independent execution unit (a web request, a video frame processing, a GUI event, a source file to compile) but not all your application in completeness, there is a function std::panic::catch_unwind that invokes a closure, capturing the cause of an unwinding panic if one occurs.
let result = panic::catch_unwind(|| {
panic!("oh no!");
});
assert!(result.is_err());
I would not grant this closure write access to any variables that could outlive it, or any other otherwise global state.
The documentation also says the function also may not be able to catch some kinds of panic.
I'm writing my first rust program and as expected I'm having problems making the borrow checker happy. Here is what I'm trying to do:
I would like to have a function that allocates some array, stores the array in some global data structure, and returns a reference to it. Example:
static mut global_data = ...
fn f() -> &str {
let s = String::new();
global.my_string = s;
return &s;
};
Is there any way to make something like this work? If not, what is "the rust way"(tm) to get an array and a pointer into it?
Alternatively, is there any documentation I could read? The rust book is unfortunately very superficial on most topics.
There are a couple things wrong with your code:
Using global state is very unidiomatic in rust. It can be done in some specific scenarios, but it should never be a go to method. You cold try wrapping your state in Rc or Arc and share it this way in your program. If you also want to mutate this state (as you show in your example) you must to wrap it also in some kind of interior mutability type. So try Rc<RefCell<State>> if you want to use state in only one thread or Arc<Mutex<State>> if you want to use it from multiple different threads.
Accessing mutable static memory is unsafe. So even the following code won't compile:
static mut x: i32 = 0;
// neither of this lines work!
println!("{}", x);
x = 42;
You must use unsafe to access or modify any static mutable variables, because you must de facto prove to the compiler that you assure it that no data races (from accessing this data from different threads) will occur.
I can't be sure, since you didn't show what type is global_data, but I assume, that my_string is a field of type String. When you write
let s = String::new();
global.my_string = s;
You move ownership of that string to the global. You therefore cannot return (or even create) reference to it. You must do this though it's new owner. &global.my_string could work, but not if you do what I written in 1. You could try to return RefMut of MutexGuard, but that is probably not what you want.
Okay, just in case someone else is having the same question, the following code seems to work:
struct foo {
b : Option<Box<u32>>,
}
static mut global : foo = foo { b : None };
fn f<'a>() -> &'a u32 {
let b : Box<u32> = Box::new(5);
unsafe {
global.b = Some(b);
match &global.b {
None => panic!(""),
Some(a) => return &a,
}
}
}
At least it compiles. Hopefully it will also do the right thing when run.
I'm aware that this is not how you are supposed to do things in rust. But I'm currently trying to figure out how to implement various data structures from scratch, and the above is just a reduced example of one of the problems I encountered.
The code case is from rustlings 'quiz2.rs'. I known command in ‘for(string,command)’ is borrowed from vector iterator. The command is borrowed, but why the 'n' Append(n) is also borrowed?
pub fn transformer(input: Vec<(String, Command)>) -> Vec<String> {
// TODO: Complete the output declaration!
let mut output: Vec<String> = vec![];
for (string, command) in input.iter() {
// TODO: Complete the function body. You can do it!
match command {
Command::Uppercase => output.push(string.to_uppercase()),
Command::Trim => output.push(string.trim().to_string()),
Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(*n);
output.push(can_mv_str);
}
}
}
output
}
First, Vec::iter() returns an iterator over references to the elements of the vector, that is, &(String, Command).
Then, whenever you write a pattern for some specific structure, like the 2-element tuple (string, command) in the for loop, but the input is a reference to that structure, Rust matches "through" the reference and automatically gives you references to the elements (because it's not possible in general to not get references, since not every type is Copy).
So, the type of command is &Command. Then the same thing happens to the match command { and every variable binding in the match's pattern (that is, n) will be a reference too.
If you want to avoid this, what you have to do is explicitly write out matching against the references:
match command {
...
&Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(n);
output.push(can_mv_str);
}
}
Or, you can dereference the input to the match (this won't necessarily try to move out of the reference — as long as you don't bind any non-Copy values):
match *command {
...
Command::Append(n) => {
let can_mv_str = string.to_string() + &"bar".repeat(n);
output.push(can_mv_str);
}
}
Finally, if you want to completely avoid the magic and write out a program that is doing the whole thing explicitly, you also need to adjust the for pattern:
for &(ref string, ref command) in input.iter() {
The ref means "please don't try to move this value out of what I'm matching; just give me a reference to it. It's rarely seen in modern Rust because the automatic matching behavior I'm talking about makes it mostly unnecessary. This feature of Rust is called “match ergonomics”, because it saves you from writing a lot of & and ref all the time. But, as you've seen, it can lead to surprising behavior, and the old explicit style also lets you avoid dealing with needless references to Copy types like integers.
If you'd like to try writing Rust without ever using match ergonomics, to understand “what's really going on”, you can enable a Clippy restriction lint to mark any places where the pattern doesn't actually fit the type of what it's matching:
#[warn(clippy::pattern_type_mismatch)]
and run cargo clippy to see the new warnings. You'll probably find that there's quite a lot of patterns that are implicitly working on references!
This is because of RFC 2005. Before that, there used to be special syntax of ref and ref mut when you wanted to take a reference to an inner field in match.
What happens here is that your command is an &Command. You match on it but the arms are all Command. So command gets de-referenced automatically. But then, in Command::Append you take ownership of the inner n. This cannot happen as your command was a reference. So rust gives you a reference to n.
You can fix this in multiple ways. The easiest is to dereference the n yourself, like so:
match command {
Command::Append(&n) => ..., // n is owned here
...
}
This works when n is Copy. You can also do a let n = n.clone() in the match body itself if n is not Copy but is Clone.
You can also take ownership of command, like so:
match *command { // if Command is Copy
Command::Append(n) => ..., // n is owned here
...
}
// OR
match command.clone() { // if Command is Clone
Command::Append(n) => ..., // n is owned here
...
}
If you cannot do any of the above, then you will need to work with the reference itself or maybe change your iterator from input.iter() to input.into_iter() to get an owned Command from the start.
I'm new to the Rust language and as I usually do when trying to pick up a language, I like to go through Euler Project questions. I want to get familiar with cargo and everything it offers, so I've created a cargo project called euler-project.
On startup, I want the program to ask the user which solution to run and have it run a function in the code that corresponds to the solution requested by the user.
I like to avoid huge chains of if / else if / else blocks, so I thought the match function would work well. Here's what I have.
use std::io;
fn main() {
// Solution selection. Every solution will be selectable here
let mut selection = String::new();
// Enum to hold every solved problem number for match control flow
enum Solutions {
P1, P2,
}
loop {
println!("Select the solution you would like to run. (Example: '32' would be Problem 32)");
io::stdin()
.read_line(&mut selection)
.expect("Input should be an integer.");
match selection {
Solutions::P1 => p1(),
Solutions::P2 => p2(),
}
}
}
fn p1() {
println!("p1")
}
fn p2() {
}
Currently this produces an error as follows:
...
21 | match selection {
| --------- this expression has type `std::string::String`
22 | Solutions::P1 => p1(),
| ^^^^^^^^^^^^^ expected struct `std::string::String`, found enum `main::Solutions`
What am I doing wrong here? If you know a better option for doing this type of control, please suggest it to me. I am also curious to know if there is anything similar to Python's interactive console mode that allows a user to run the code in the terminal, and to make function calls by simply typing function names and hitting enter.
You're comparing apples and oranges here. On the one hand, you have the string you have read from the user, and on the other hand you have values of type Solutions, but nowhere do you tell the compiler how to compare the two. The easiest way to do what you want is just to compare strings directly:
match selection.trim() {
"1" => p1(),
"2" => p2(),
_ => panic!("{} does not designate a valid problem!", selection),
}
Note the call to trim: the string returned by read_line includes the trailing newline, which you need to remove so that the comparisons will work.
Note also that you will need to call selection.clear() before read_line, otherwise the next iteration of the loop will append to the string instead of replacing it.
You can't match an enum with a String. You could try something like:
match selection.trim().parse::<i32>() {
Ok(x) if x == (Solutions::P1 as i32) => p1(),
Ok(x) if x == (Solutions::P2 as i32)=> p2(),
x => panic!{x},
}
This extremely simple Rust program:
fn main() {
let c = "hello";
println!(c);
}
throws the following compile-time error:
error: expected a literal
--> src/main.rs:3:14
|
3 | println!(c);
| ^
In previous versions of Rust, the error said:
error: format argument must be a string literal.
println!(c);
^
Replacing the program with:
fn main() {
println!("Hello");
}
Works fine.
The meaning of this error isn't clear to me and a Google search hasn't really shed light on it. Why does passing c to the println! macro cause a compile time error? This seems like quite unusual behaviour.
This should work:
fn main() {
let c = "hello";
println!("{}", c);
}
The string "{}" is a template where {} will be replaced by the next argument passed to println!.
TL;DR If you don't care why and just want to fix it, see the sibling answer.
The reason that
fn main() {
let c = "hello";
println!(c);
}
Cannot work is because the println! macro looks at the string at compile time and verifies that the arguments and argument specifiers match in amount and type (this is a very good thing!). At this point in time, during macro evaluation, it's not possible to tell that c came from a literal or a function or what have you.
Here's an example of what the macro expands out to:
let c = "hello";
match (&c,) {
(__arg0,) => {
#[inline]
#[allow(dead_code)]
static __STATIC_FMTSTR: &'static [&'static str] = &[""];
::std::io::stdio::println_args(&::std::fmt::Arguments::new(
__STATIC_FMTSTR,
&[::std::fmt::argument(::std::fmt::Show::fmt, __arg0)]
))
}
};
I don't think that it's actually impossible for the compiler to figure this out, but it would probably take a lot of work with potentially little gain. Macros operate on portions of the AST and the AST only has type information. To work in this case, the AST would have to include the source of the identifier and enough information to determine it's acceptable to be used as a format string. In addition, it might interact poorly with type inference - you'd want to know the type before it's been picked yet!
The error message asks for a "string literal". What does the word "literal" mean? asks about what that means, which links to the Wikipedia entry:
a literal is a notation for representing a fixed value in source code
"foo" is a string literal, 8 is a numeric literal. let s = "foo" is a statement that assigns the value of a string literal to an identifier (variable). println!(s) is a statement that provides an identifier to the macro.
If you really want to define the first argument of println! in one place, I found a way to do it. You can use a macro:
macro_rules! hello {() => ("hello")};
println!(hello!());
Doesn't look too useful here, but I wanted to use the same formatting in a few places, and in this case the method was very helpful:
macro_rules! cell_format {() => ("{:<10}")}; // Pads with spaces on right
// to fill up 10 characters
println!(cell_format!(), "Foo");
println!(cell_format!(), 456);
The macro saved me from having to duplicate the formatting option in my code.
You could also, obviously, make the macro more fancy and take arguments if necessary to print different things with different arguments.
If your format string will be reused only a moderate number of times, and only some variable data will be changed, then a small function may be a better option than a macro:
fn pr(x: &str) {
println!("Some stuff that will always repeat, something variable: {}", x);
}
pr("I am the variable data");
Outputs
Some stuff that will always repeat, something variable: I am the variable data