This question already has an answer here:
Why Rust allows declaring same variable name twice in a scope? [duplicate]
(1 answer)
Closed 1 year ago.
Hello fellow Rustaceans!
How it is possible that i can write that in Rust:
let mut v : Vec<u8> = Vec::new();
v.push(0);
v.push(1);
v.push(2);
let s = &v;
print!("{:?} - ", s); // will output "[0, 1, 2]"
let s = &v[1..];
println!("{:?}", s); // will screen "[1, 2]"
Normaly variables are immutable by default, no ?
And here i can change the value of the slice (s)
but normaly s is declared than variable with "let" ?
what's wrong ?
As pointed out in the comments, you're making a new variable called s. Up to renaming, your code is equivalent to
let mut v : Vec<u8> = Vec::new();
v.push(0);
v.push(1);
v.push(2);
let s = &v;
print!("{:?} - ", s); // will output "[0, 1, 2]"
let my_unrelated_s_variable = &v[1..];
println!("{:?}", my_unrelated_s_variable); // will screen "[1, 2]"
The two s you declared are, as far as the Rust compiler is concerned, unrelated variables. In fact, we could even give the second one a different type.
let s = &v;
let s = 42; // This one's an integer, but it's fine
This sort of shadowing is very common in Rust when we want to augment a particular value but want to respect immutability, as it guarantees we aren't actually changing anything in memory while allowing us the convenience of reusing variable names. For example, I often find myself doing things like this.
fn example(input: &str) {
let input = some_complicated_parsing_step(input)?;
...
}
The argument input is a string, and I want to convert it to something (maybe parse it as JSON, maybe read an integer from it, etc.). Once I do that, I have no use for the original string anymore, and it's reasonable to call the result of parsing input, as it is still the input I was given, just in a different form now.
Related
This question already has an answer here:
In Rust, what's the difference between "shadowing" and "mutability"?
(1 answer)
Closed 2 years ago.
I was quite surprised to find that the following program will happily compile and run (using "cargo 1.42.0 (86334295e 2020-01-31)."), outputting:
5
k
The variable x which is not declared as mut is not only reassigned but reassigned with a different type.
Is there some reason why you are allowed to do this?
fn main() {
let x = 5;
println!("{}", x);
let t: (i32, f64, char) = (2, 3.14, 'k');
let (_,_,x) = t;
println!("{}", x);
}
This is called "shadowing a variable"
(https://doc.rust-lang.org/book/ch03-01-variables-and-mutability.html#shadowing)
It can also been shown as simply as so:
let x = 5;
let x = 'k';
It actually comes in handy often. For instance, you can reuse an identifier after you are done using its initially assigned value:
let two_times_five = 2 * 5; // type i32
let two_times_five = two_times_five.to_string(); // type String
The compiler will still enforce strong typing; accesses to two_times_five before its redefinition will be accessing an i32, accesses afterward will be accessing a String.
There are also times when you don't want a variable to be mutable, but at some point you want to assign it a different value. Using variable shadowing rather than let mut means you know the variable is not changed in between its definitions, regardless of what functions it's passed into or methods are called on it.
This question already has answers here:
Meaning of '&variable' in arguments/patterns
(1 answer)
What is the difference between `e1` and `&e2` when used as the for-loop variable?
(1 answer)
What's the difference between ref and & when assigning a variable from a reference?
(3 answers)
Closed 3 years ago.
I came across below example in Rust book.
for &item in list.iter() {
if item > largest {
largest = item;
}
}
I suppose it means list.iter() returns the reference to the elements in the list hence &item but while comparing it with largest number why are we not using *item? Also, when I change the &item to item in the first line I am forced to use *item in 2nd and 3rd line by the compiler.
I have seen another example online.
(0..).map(|x| x * x)
.take_while(|&x| x <= limit)
.filter(|x| is_even(*x))
Here the closure in take_while accepts &x but uses x directly but the closure in filter takes x without reference but passes *x to is_even.
So how does this work in Rust?
What you are seeing here is called destructuring. This is a feature where you can take apart a structure with a pattern.
You probably already saw something like let (a, b) = returns_a_tuple();. Here, a tuple is destructured. You can also destructure references:
// The comments at the end of the line tell you the type of the variable
let i = 3; // : i32
let ref_i = &i; // : &i32
let ref_ref_i = &ref_i; // : &&i32
let &x = ref_i; // : i32
let &y = ref_ref_i; // : &i32
let &&z = ref_ref_i; // : i32
// All of these error because we try to destructure more layers of references
// than there are.
let &a = i;
let &&b = ref_i;
let &&&c = ref_ref_i;
This has the counter-intuitive effect that the more & you add in the pattern, the fewer & will the type of the variable have. But it does make sense in the context of destructuring: when you already mention the structure in the pattern, the structure won't be in the bound variables anymore.
(It is worth noting that this "destructuring references away" only works with referee types that are Copy. Otherwise you will get a "cannot move out of borrowed content" error.)
Now what does that have to do with your for loop and the closures? Turns out: patterns are everywhere. The slot between for and in in the for loop is a pattern, and arguments of functions and closures are pattern as well! This works:
// Destructuring a tuple in the for loop pattern
let v = vec![3];
for (i, elem) in v.iter().enumerate() {}
// Destructuring an array in the function argument (works the same for closures)
fn foo([x, y, z]: [f32; 3]) {}
I suppose it means list.iter() returns the reference to the elements in the list
Exactly.
... hence &item
"hence" is not correct here. The author of this code didn't want to work with the reference to the item, but instead work with the real value. So they added the & in the pattern to destructure the reference away.
but while comparing it with largest number why are we not using *item?
Yes, because the reference was already removed by the destructuring pattern.
Also, when I change the &item to item in the first line I am forced to use *item in 2nd and 3rd line by the compiler.
Yes, because now the pattern doesn't destructure the reference anymore, so item is a reference again. This is the basic gist with all of this: most of the time you can either remove the reference in the pattern by adding a & or you can remove the reference when using the variable by adding a *.
Here the closure in take_while accepts &x but uses x directly but the closure in filter takes x without reference but passes *x to is_even.
It should be clear by now why that is, right? The take_while closure removes the reference via destructuring in the pattern while the filter closure does it via standard dereferencing.
You can read more about all of this in this chapter of the book.
I tried to use a String vector inside another vector:
let example: Vec<Vec<String>> = Vec::new();
for _number in 1..10 {
let mut temp: Vec<String> = Vec::new();
example.push(temp);
}
I should have 10 empty String vectors inside my vector, but:
example.get(0).push(String::from("test"));
fails with
error[E0599]: no method named `push` found for type `std::option::Option<&std::vec::Vec<std::string::String>>` in the current scope
--> src/main.rs:9:20
|
9 | example.get(0).push(String::from("test"));
| ^^^^
Why does it fail? Is it even possible to have an vector "inception"?
I highly recommend reading the documentation of types and methods before you use them. At the very least, look at the function's signature. For slice::get:
pub fn get<I>(&self, index: I) -> Option<&<I as SliceIndex<[T]>>::Output>
where
I: SliceIndex<[T]>,
While there's some generics happening here, the important part is that the return type is an Option. An Option<Vec> is not a Vec.
Refer back to The Rust Programming Language's chapter on enums for more information about enums, including Option and Result. If you wish to continue using the semantics of get, you will need to:
Switch to get_mut as you want to mutate the inner vector.
Make example mutable.
Handle the case where the indexed value is missing. Here I use an if let.
let mut example: Vec<_> = std::iter::repeat_with(Vec::new).take(10).collect();
if let Some(v) = example.get_mut(0) {
v.push(String::from("test"));
}
If you want to kill the program if the value is not present at the index, the shortest thing is to use the index syntax []:
example[0].push(String::from("test"));
I set myself a little task to acquire some basic Rust knowledge. The task was:
Read some key-value pairs from stdin and put them into a hashmap.
This, however, turned out to be a trickier challenge than expected. Mainly due to the understanding of lifetimes. The following code is what I currently have after a few experiments, but the compiler just doesn't stop yelling at me.
use std::io;
use std::collections::HashMap;
fn main() {
let mut input = io::stdin();
let mut lock = input.lock();
let mut lines_iter = lock.lines();
let mut map = HashMap::new();
for line in lines_iter {
let text = line.ok().unwrap();
let kv_pair: Vec<&str> = text.words().take(2).collect();
map.insert(kv_pair[0], kv_pair[1]);
}
println!("{}", map.len());
}
The compiler basically says:
`text` does not live long enough
As far as I understand, this is because the lifetime of 'text' is limited to the scope of the loop.
The key-value pair that I'm extracting within the loop is therefore also bound to the loops boundaries. Thus, inserting them to the outer map would lead to a dangling pointer since 'text' will be destroyed after each iteration. (Please tell me if I'm wrong)
The big question is: How to solve this issue?
My intuition says:
Make an "owned copy" of the key value pair and "expand" it's lifetime to the outer scope .... but I have no idea how to achieve this.
The lifetime of 'text' is limited to the scope of the loop. The key-value pair that I'm extracting within the loop is therefore also bound to the loops boundaries. Thus, inserting them to the outer map would lead to an dangling pointer since 'text' will be destroyed after each iteration.
Sounds right to me.
Make an "owned copy" of the key value pair.
An owned &str is a String:
map.insert(kv_pair[0].to_string(), kv_pair[1].to_string());
Edit
The original code is below, but I've updated the answer above to be more idiomatic
map.insert(String::from_str(kv_pair[0]), String::from_str(kv_pair[1]));
In Rust 1.1 the function words was marked as deprecated. Now you should use split_whitespace.
Here is an alternative solution which is a bit more functional and idiomatic (works with 1.3).
use std::io::{self, BufRead};
use std::collections::HashMap;
fn main() {
let stdin = io::stdin();
// iterate over all lines, "change" the lines and collect into `HashMap`
let map: HashMap<_, _> = stdin.lock().lines().filter_map(|line_res| {
// convert `Result` to `Option` and map the `Some`-value to a pair of
// `String`s
line_res.ok().map(|line| {
let kv: Vec<_> = line.split_whitespace().take(2).collect();
(kv[0].to_owned(), kv[1].to_owned())
})
}).collect();
println!("{}", map.len());
}
I'm trying to get my head around Rust. I've got an alpha version of 1.
Here's the problem I'm trying to program: I have a vector of floats. I want to set up some threads asynchronously. Each thread should wait for the number of seconds specified by each element of the vector, and return the value of the element, plus 10. The results need to be in input order.
It's an artificial example, to be sure, but I wanted to see if I could implement something simple before moving onto more complex code. Here is my code so far:
use std::thread;
use std::old_io::timer;
use std::time::duration::Duration;
fn main() {
let mut vin = vec![1.4f64, 1.2f64, 1.5f64];
let mut guards: Vec<thread::scoped> = Vec::with_capacity(3);
let mut answers: Vec<f64> = Vec::with_capacity(3);
for i in 0..3 {
guards[i] = thread::scoped( move || {
let ms = (1000.0f64 * vin[i]) as i64;
let d = Duration::milliseconds(ms);
timer::sleep(d);
println!("Waited {}", vin[i]);
answers[i] = 10.0f64 + (vin[i] as f64);
})};
for i in 0..3 {guards[i].join(); };
for i in 0..3 {println!("{}", vin[i]); }
}
So the input vector is [1.4, 1.2, 1.5], and I'm expecting the output vector to be [11.4, 11.2, 11.5].
There appear to be a number of problems with my code, but the first one is that I get a compilation error:
threads.rs:7:25: 7:39 error: use of undeclared type name `thread::scoped`
threads.rs:7 let mut guards: Vec<thread::scoped> = Vec::with_capacity(3);
^~~~~~~~~~~~~~
error: aborting due to previous error
There also seem to be a number of other problems, including using vin within a closure. Also, I have no idea what move does, other than the fact that every example I've seen seems to use it.
Your error is due to the fact that thread::scoped is a function, not a type. What you want is a Vec<T> where T is the result type of the function. Rust has a neat feature that helps you here: It automatically detects the correct type of your variables in many situations.
If you use
let mut guards = Vec::with_capacity(3);
the type of guards will be chosen when you use .push() the first time.
There also seem to be a number of other problems.
you are accessing guards[i] in the first for loop, but the length of the guards vector is 0. Its capacity is 3, which means that you won't have any unnecessary allocations as long as the vector never contains more than 3 elements. use guards.push(x) instead of guards[i] = x.
thread::scoped expects a Fn() -> T, so your closure can return an object. You get that object when you call .join(), so you don't need an answer-vector.
vin is moved to the closure. Therefore in the second iteration of the loop that creates your guards, vin isn't available anymore to be moved to the "second" closure. Every loop iteration creates a new closure.
i is moved to the closure. I have no idea what's going on there. But the solution is to let inval = vin[i]; outside the closure, and then use inval inside the closure. This also solves Point 3.
vin is mutable. Yet you never mutate it. Don't bind variables mutably if you don't need to.
vin is an array of f64. Therefore (vin[i] as f64) does nothing. Therefore you can simply use vin[i] directly.
join moves out of the guard. Since you cannot move out of an array, your cannot index into an array of guards and join the element at the specified index. What you can do is loop over the elements of the array and join each guard.
Basically this means: don't iterate over indices (for i in 1..3), but iterate over elements (for element in vector) whenever possible.
All of the above implemented:
use std::thread;
use std::old_io::timer;
use std::time::duration::Duration;
fn main() {
let vin = vec![1.4f64, 1.2f64, 1.5f64];
let mut guards = Vec::with_capacity(3);
for inval in vin {
guards.push(thread::scoped( move || {
let ms = (1000.0f64 * inval) as i64;
let d = Duration::milliseconds(ms);
timer::sleep(d);
println!("Waited {}", inval);
10.0f64 + inval
}));
}
for guard in guards {
let answer = guard.join();
println!("{}", answer);
};
}
In supplement of Ker's answer: if you really need to mutate arrays within a thread, I suppose the most closest valid solution for your task will be something like this:
use std::thread::spawn;
use std::old_io::timer;
use std::sync::{Arc, Mutex};
use std::time::duration::Duration;
fn main() {
let vin = Arc::new(vec![1.4f64, 1.2f64, 1.5f64]);
let answers = Arc::new(Mutex::new(vec![0f64, 0f64, 0f64]));
let mut workers = Vec::new();
for i in 0..3 {
let worker_vin = vin.clone();
let worker_answers = answers.clone();
let worker = spawn( move || {
let ms = (1000.0f64 * worker_vin[i]) as i64;
let d = Duration::milliseconds(ms);
timer::sleep(d);
println!("Waited {}", worker_vin[i]);
let mut answers = worker_answers.lock().unwrap();
answers[i] = 10.0f64 + (worker_vin[i] as f64);
});
workers.push(worker);
}
for worker in workers { worker.join().unwrap(); }
for answer in answers.lock().unwrap().iter() {
println!("{}", answer);
}
}
In order to share vectors between several threads, I have to prove, that these vectors outlive all of my threads. I cannot use just Vec, because it will be destroyed at the end of main block, and another thread could live longer, possibly accessing freed memory. So I took Arc reference counter, which guarantees, that my vectors will be destroyed only when the counter downs to zero.
Arc allows me to share read-only data. In order to mutate answers array, I should use some synchronize tools, like Mutex. That is how Rust prevents me to make data races.