What's the difference between var and _var in Rust? - rust

Given this:
fn main() {
let variable = [0; 15];
}
The Rust compiler produces this warning:
= note: #[warn(unused_variables)] on by default
= note: to avoid this warning, consider using `_variable` instead
What's the difference between variable and _variable?

The difference is an underscore at the front, which causes the Rust compiler to allow it to be unused. It is kind of a named version of the bare underscore _ which can be used to ignore a value.
However, _name acts differently than _. The plain underscore drops the value immediately while _name acts like any other variable and drops the value at the end of the scope.
An example of how it does not act exactly the same as a plain underscore:
struct Count(i32);
impl Drop for Count {
fn drop(&mut self) {
println!("dropping count {}", self.0);
}
}
fn main() {
{
let _a = Count(3);
let _ = Count(2);
let _c = Count(1);
}
{
let _a = Count(3);
let _b = Count(2);
let _c = Count(1);
}
}
prints the following (playground):
dropping count 2
dropping count 1
dropping count 3
dropping count 1
dropping count 2
dropping count 3

The key difference between _variable and variable is that first one tells compiler not to give any warnings if we do not use it in our code. Example:
// src/main.rs
fn main() {
let _x = 1;
let y = 2;
}
Compiling main.rs gives:
warning: unused variable: `y`
--> src/main.rs:3:9
|
3 | let y = 2;
| ^ help: if this is intentional, prefix it with an underscore: `_y`
|
= note: `#[warn(unused_variables)]` on by default
The more interesting case is when we are comparing _ with _variable.
Ignoring an Unused Variable by Starting Its Name with _:
The syntax _x still binds the value to the variable, whereas _ doesn’t bind at all.
Consider example:
// src/main.rs
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_s) = s {
println!("found a string");
}
println!("{:?}", s);
}
When we try to compile main.rs we get error:
error[E0382]: borrow of moved value: `s`
--> src/main.rs:8:22
|
4 | if let Some(_s) = s {
| -- value moved here
...
8 | println!("{:?}", s);
| ^ value borrowed here after partial move
|
= note: move occurs because value has type `std::string::String`, which does not implement the `Copy` trait
help: borrow this field in the pattern to avoid moving `s.0`
|
4 | if let Some(ref _s) = s {
| ^^^
Aha! The syntax _x still binds the value to the variable, which means that we are moving the ownership of s to _s, thus, we can no longer access variable s anymore; which happens when we try to print value of s.
The correct way of doing the above is:
// src/main.rs
fn main() {
let s = Some(String::from("Hello!"));
if let Some(_) = s {
println!("found a string");
}
println!("{:?}", s);
}
Above code works just fine. s does not get moved into _, so we can still access it later.
Sometimes I use _ with iterators:
fn main() {
let v = vec![1, 2, 3];
let _ = v
.iter()
.map(|x| {
println!("{}", x);
})
.collect::<Vec<_>>();
}
Compiling gives result:
1
2
3
When doing more complex operations on iterable types above example acts as utility for me.

Related

annotate type for "for loop" variables [duplicate]

C++ example:
for (long i = 0; i < 101; i++) {
//...
}
In Rust I tried:
for i: i64 in 1..100 {
// ...
}
I could easily just declare a let i: i64 = var before the for loop
but I'd rather learn the correct way to doing this, but this resulted in
error: expected one of `#` or `in`, found `:`
--> src/main.rs:2:10
|
2 | for i: i64 in 1..100 {
| ^ expected one of `#` or `in` here
You can use an integer suffix on one of the literals you've used in the range. Type inference will do the rest:
for i in 1i64..101 {
println!("{}", i);
}
No, it is not possible to declare the type of the variable in a for loop.
Instead, a more general approach (e.g. applicable also to enumerate()) is to introduce a let binding by destructuring the item inside the body of the loop.
Example:
for e in bytes.iter().enumerate() {
let (i, &item): (usize, &u8) = e; // here
if item == b' ' {
return i;
}
}
If your loop variable happens to be the result of a function call that returns a generic type:
let input = ["1", "two", "3"];
for v in input.iter().map(|x| x.parse()) {
println!("{:?}", v);
}
error[E0284]: type annotations required: cannot resolve `<_ as std::str::FromStr>::Err == _`
--> src/main.rs:3:37
|
3 | for v in input.iter().map(|x| x.parse()) {
| ^^^^^
You can use a turbofish to specify the types:
for v in input.iter().map(|x| x.parse::<i32>()) {
// ^^^^^^^
println!("{:?}", v);
}
Or you can use the fully-qualified syntax:
for v in input.iter().map(|x| <i32 as std::str::FromStr>::from_str(x)) {
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
println!("{:?}", v);
}
See also:
How do I imply the type of the value when there are no type parameters or ascriptions?
There used to be a discussion where this was requested, which was followed up by an actual RFC.
It seems like the discussion was postponed, though, because not enough people really cared about the topic.
Currently, if you absolutely want to annotate, it seems like the best option you have is:
fn main() {
let my_vec: Vec<i32> = vec![-1, 22, -333];
for i in my_vec.iter() {
let _: &i32 = i;
println!("{}", i);
}
}
As you can see, this fails if the type doesn't match:
fn main() {
let my_vec: Vec<i32> = vec![-1, 22, -333];
for i in my_vec.iter() {
let _: &i16 = i;
println!("{}", i);
}
}
--> src/main.rs:4:23
|
4 | let _: &i16 = i;
| ---- ^ expected `i16`, found `i32`
| |
| expected due to this
|
= note: expected reference `&i16`
found reference `&i32`
Of course due to automatic dereferencing this method cannot differentiate between &i32 and &&i32, which might be a problem in some cases:
fn main() {
let my_vec: Vec<i32> = vec![-1, 22, -333];
for i in my_vec.iter() {
let _: &i32 = &i; // Compiles, but the right side is &&i32
println!("{}", i);
}
}
But in general this should bring enough confidence to potential reviewers, in my opinion.
Try casting with as:
for i in 1..100 as i64 {
// ...
}

How to iteratively call a function with ref argument and update state?

This is a minimal example. I have a function foo that takes a reference of a vector and returns a brand new vector. Then, there's another function bar that iteratively calls foo and update its state. But I cannot get it to compile.
fn foo(input: &Vec<i32>) -> Vec<i32> {
let len = input.len();
return input[0..len-1].to_vec();
}
fn bar() {
let input = vec![1,2,3,4,5];
let mut out = &input;
for _ in 0..2 {
out = foo(out);
}
}
Gives this error:
78 | out = foo(out);
| ^^^^^^^^
| |
| expected `&Vec<i32>`, found struct `Vec`
| help: consider borrowing here: `&foo(out)`
So that makes sense since out has a mismatched type of &Vec<i32>. Now, if I add an ampersand in front of the foo(out) call, then I got a different error:
78 | out = &foo(out);
| ^^^^---^- temporary value is freed at the end of this statement
| | |
| | borrow later used here
| creates a temporary which is freed while still in use
What is the right way to fix this?
The clean way, if possible, is to consistently hold onto the actual value instead of a reference:
fn bar() {
let input = vec![1,2,3,4,5];
let mut out = input;
for _ in 0..2 {
out = foo(&out);
}
}
or, equivalently,
fn bar() {
let input = vec![1,2,3,4,5];
let out = (0..2).fold(input, |prev, _| foo(&prev));
}
But if you need to continue using input afterwards, then you’ll have to find some other way to make the return value of foo live longer than the loop, e.g.
fn bar() {
let input = vec![1,2,3,4,5];
let mut out_storage;
let mut out = &input;
for _ in 0..2 {
out_storage = foo(out);
out = &out_storage;
}
}

A variable modified by two closures

Consider the following (contrived) way to increment x by 9.
fn main() {
let mut x = 0;
let mut f = || {
x += 4;
};
let _g = || {
f();
x += 5;
};
}
error[E0499]: cannot borrow `x` as mutable more than once at a time
--> x.rs:6:12
|
3 | let mut f = || {
| -- first mutable borrow occurs here
4 | x += 4;
| - first borrow occurs due to use of `x` in closure
5 | };
6 | let _g = || {
| ^^ second mutable borrow occurs here
7 | f();
| - first borrow later captured here by closure
8 | x += 5;
| - second borrow occurs due to use of `x` in closure
error: aborting due to previous error
For more information about this error, try `rustc --explain E0499`.
So, it does not work. How to make an algorithm like the above that would modify a variable in a closure and call another closure from it that also modifies the variable?
In traditional languages it's easy. What to do in Rust?
The accepted answer is the most idiomatic approach, but there is also an alternative that is useful in situations when the additional argument doesn't work, for example when you need to pass the closure to third-party code that will call it without arguments. In that case you can use a Cell, a form of interior mutability:
use std::cell::Cell;
fn main() {
let x = Cell::new(0);
let f = || {
x.set(x.get() + 4);
};
let g = || {
f();
x.set(x.get() + 5);
};
f();
g();
assert_eq!(x.get(), 13);
}
By design, closures have to enclose external objects that are used in it upon creation, in our case closures have to borrow the external x object. So as compiler explained to you, upon creation of the closure f it mutably borrows x, and you can't borrow it once again when you create closure g.
In order to compile it you can't enclose any external object that you want to change. Instead you can directly pass the objects as a closure's argument (arguably it's even more readable). This way you describe that a closure accepts some object of some type, but you don't yet use/pass any actual object. This object will be borrowed only when you call the closure.
fn main() {
let mut x = 0;
let f = |local_x: &mut i32| { // we don't enclose `x`, so no borrow yet
*local_x += 4;
};
let _g = |local_x: &mut i32| { // we don't enclose `x`, so no borrow yet
f(local_x);
*local_x += 5;
};
_g(&mut x); // finally we borrow `x`, and this borrow will later move to `f`,
// so no simultaneous borrowing.
println!("{}", x); // 9
}
To expand on Alex Larionov's answer: you should think of a closure as a callable structure, anything you capture is set as a field of the structure, then implicitly dereferenced inside the function body. The way those fields are used is also what determines whether the closure is Fn, FnMut or FnOnce, basically whether the method would take &self, &mut self or self if it were written longhand.
Here
fn main() {
let mut x = 0;
let mut f = || {
x += 4;
};
// ...
}
essentially translates to:
struct F<'a> { x: &'a mut u32 }
impl F<'_> {
fn call(&mut self) {
*self.x += 4
}
}
fn main() {
let mut x = 0;
let mut f = F { x: &mut x };
// ...
}
from this, you can see that as soon as f is created, x is mutably borrowed, with all that implies.
And with this partial desugaring, we can see essentially the same error: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e129f19f25dc61de8a6f42cdca1f67b5
If we use the relevant unstable features on nightly we can get just a bit closer. That is pretty much what rustc does for us under the hood.

Iterate through a whole file one character at a time

I'm new to Rust and I'm struggle with the concept of lifetimes. I want to make a struct that iterates through a file a character at a time, but I'm running into issues where I need lifetimes. I've tried to add them where I thought they should be but the compiler isn't happy. Here's my code:
struct Advancer<'a> {
line_iter: Lines<BufReader<File>>,
char_iter: Chars<'a>,
current: Option<char>,
peek: Option<char>,
}
impl<'a> Advancer<'a> {
pub fn new(file: BufReader<File>) -> Result<Self, Error> {
let mut line_iter = file.lines();
if let Some(Ok(line)) = line_iter.next() {
let char_iter = line.chars();
let mut advancer = Advancer {
line_iter,
char_iter,
current: None,
peek: None,
};
// Prime the pump. Populate peek so the next call to advance returns the first char
let _ = advancer.next();
Ok(advancer)
} else {
Err(anyhow!("Failed reading an empty file."))
}
}
pub fn next(&mut self) -> Option<char> {
self.current = self.peek;
if let Some(char) = self.char_iter.next() {
self.peek = Some(char);
} else {
if let Some(Ok(line)) = self.line_iter.next() {
self.char_iter = line.chars();
self.peek = Some('\n');
} else {
self.peek = None;
}
}
self.current
}
pub fn current(&self) -> Option<char> {
self.current
}
pub fn peek(&self) -> Option<char> {
self.peek
}
}
fn main() -> Result<(), Error> {
let file = File::open("input_file.txt")?;
let file_buf = BufReader::new(file);
let mut advancer = Advancer::new(file_buf)?;
while let Some(char) = advancer.next() {
print!("{}", char);
}
Ok(())
}
And here's what the compiler is telling me:
error[E0515]: cannot return value referencing local variable `line`
--> src/main.rs:37:13
|
25 | let char_iter = line.chars();
| ---- `line` is borrowed here
...
37 | Ok(advancer)
| ^^^^^^^^^^^^ returns a value referencing data owned by the current function
error[E0597]: `line` does not live long enough
--> src/main.rs:49:34
|
21 | impl<'a> Advancer<'a> {
| -- lifetime `'a` defined here
...
49 | self.char_iter = line.chars();
| -----------------^^^^--------
| | |
| | borrowed value does not live long enough
| assignment requires that `line` is borrowed for `'a`
50 | self.peek = Some('\n');
51 | } else {
| - `line` dropped here while still borrowed
error: aborting due to 2 previous errors
Some errors have detailed explanations: E0515, E0597.
For more information about an error, try `rustc --explain E0515`.
error: could not compile `advancer`.
Some notes:
The Chars iterator borrows from the String it was created from. So you can't drop the String while the iterator is alive. But that's what happens in your new() method, the line variable owning the String disappears while the iterator referencing it is stored in the struct.
You could also try storing the current line in the struct, then it would live long enough, but that's not an option – a struct cannot hold a reference to itself.
Can you make a char iterator on a String that doesn't store a reference into the String? Yes, probably, for instance by storing the current position in the string as an integer – it shouldn't be the index of the char, because chars can be more than one byte long, so you'd need to deal with the underlying bytes yourself (using e.g. is_char_boundary() to take the next bunch of bytes starting from your current index that form a char).
Is there an easier way? Yes, if performance is not of highest importance, one solution is to make use of Vec's IntoIterator instance (which uses unsafe magic to create an object that hands out parts of itself) :
let char_iter = file_buf.lines().flat_map(|line_res| {
let line = line_res.unwrap_or(String::new());
line.chars().collect::<Vec<_>>()
});
Note that just returning line.chars() would have the same problem as the first point.
You might think that String should have a similar IntoIterator instance, and I wouldn't disagree.

How to destructure tuple struct with reference

I'm trying to use the hyper library to make some requests. The Headers::get() method returns Option<&H>, where H is a tuple struct with one field. I can use if let Some() to destructure the Option. But how do we destructure the &H? Sure I could always access the field with .0, but I'm curious if Rust has a syntax to do this.
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let &s(bar) = f(&my_struct2); // this does not work
let baz = &my_struct2.0; // this works
}
When you try to compile this, the Rust compiler will tell you how to fix the error with a nice message:
error[E0507]: cannot move out of borrowed content
--> <anon>:11:9
|
11 | let &s(bar) = f(&my_struct2); // this does not work
| ^^^---^
| | |
| | hint: to prevent move, use `ref bar` or `ref mut bar`
| cannot move out of borrowed content
This is needed to tell the compiler that you only want a reference to the field in the struct; the default matching will perform a move and the original struct value will no longer be valid.
Let's fix the example:
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let &s(ref bar) = f(&my_struct2);
}
Another way is to dereference first and drop the &. I think this is preferred in Rust:
struct s(String);
fn f(input: &s) -> &s {
input
}
fn main() {
let my_struct1 = s("a".to_owned());
let s(foo) = my_struct1;
let my_struct2 = s("b".to_owned());
let s(ref bar) = *f(&my_struct2);
}

Resources