In Rust, how to use `find()` on a `iter_mut` - rust

How can I make this compile:
struct S {
s:String
}
fn main() {
let mut v:Vec<S>;
let cmp = "asdf";
v.iter_mut().find(|&&x| x == cmp);
// ^^^
// What to write here when using find on a iter_mut (and why?)
}
Error message:
--> src/main.rs:8:25
|
8 | v.iter_mut().find(|&&x| x == cmp);
| ^-
| ||
| |expected due to this
| types differ in mutability
| help: you can probably remove the explicit borrow: `x`
|
= note: expected mutable reference `&mut S`
found reference `&_`
For more information about this error, try `rustc --explain E0308`.
error: could not compile `asdf` due to previous error

You don't have to destructure S in the closure because that would move the String.
struct S {
s: String,
}
fn main() {
let mut v: Vec<_> = vec![S { s: "Hello".into() }, S { s: "asdf".into() }];
let cmp = "asdf";
// Will be Option<&mut S>
let _found = v.iter_mut().find(|x| x.s == cmp);
}
I added two items to the Vec since you declared v without defining it. Notice that the closure just takes x which is a &&mut, but you don't have to explicitly say that anywhere because x will be dereferenced in the body of the closure.
The expression x.s == cmp compares the String, s, from to the &str, cmp.
// Automatically dereferenced
x.s == cmp
And manually:
// Manually dereferenced. You don't have to do this for structs.
(**x).s
Further reading
Destructuring
Dereferencing
PartialEq

Related

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.

How to pass an Arc clone to a closure?

I'm trying to write a closure that uses an Arc by cloning it. Ideally I'd like to have the clone inside the closure, but I'm kinda forced to pass the original Arc, which might be the reason I'm getting the error:
use std::sync::Arc;
use std::sync::Condvar;
use std::sync::Mutex;
use std::collections::VecDeque;
type Fifo<T> = Arc<(Mutex<VecDeque<T>>, Condvar)>;
fn executor(f: Box<dyn Fn()>) {
f();
}
fn main() {
let a = Fifo::<u8>::new(
(Mutex::new(VecDeque::new()), Condvar::new())
);
let r = Box::new(||{
let f = a.clone();
f.0.lock().unwrap().push_back(0);
});
executor(r);
}
Error:
error[E0597]: `a` does not live long enough
--> src/main.rs:19:17
|
18 | let r = Box::new(||{
| -- value captured here
19 | let f = a.clone();
| ^ borrowed value does not live long enough
...
22 | executor(r);
| - cast requires that `a` is borrowed for `'static`
23 | }
| - `a` dropped here while still borrowed
error: aborting due to previous error
I thought changing to
let r = Box::new(||{
//let f = a.clone();
a.0.lock().unwrap().push_back(0);
});
would force the closure to decide to clone a, therefore fixing the problem, but I get the same error.
How can I pass an Arc to a closure?
Clone the Arc outside the closure and then move the clone into the closure. Example:
use std::collections::VecDeque;
use std::sync::Arc;
use std::sync::Condvar;
use std::sync::Mutex;
type Fifo<T> = Arc<(Mutex<VecDeque<T>>, Condvar)>;
fn executor(f: Box<dyn Fn()>) {
f();
}
fn main() {
let a = Fifo::<u8>::new((Mutex::new(VecDeque::new()), Condvar::new()));
let f = a.clone();
let r = Box::new(move || {
f.0.lock().unwrap().push_back(0);
});
executor(r);
}
playground

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 does ownership and borrowing work when making slices?

Here are two code snippets, but they show a different behavior and I couldn't understand what's going on in there. Their main function is identical. If the borrowing and ownership concept applies to one code (i.e to code 2) why not to another code i.e (code 1)?
code 1:
This code compiles with no errors and prompt the result.
fn main() {
let mut s = String::from("Hello world");
let result = first_word(&s);
s.clear();
println!("result:{:#?}", result);
}
fn first_word(s: &String) -> usize {
let s = s.as_bytes();
//println!("{:?}",s);
for (i, &item) in s.iter().enumerate() {
if item == 32 {
return i;
}
}
s.len()
}
Code 1 Output :
Finished dev [unoptimized + debuginfo] target(s) in 0.28s
Running `target/debug/rust_Slices`
result:5
Code 2:
This code won't compile and gives an error.
fn main() {
let mut s = String::from("Hello world");
let result = first_word(&s);
s.clear();
println!("{:#?}", result);
}
fn first_word(s: &String) -> &str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
Code 2 Output:
cannot borrow `s` as mutable because it is also borrowed as immutable
--> src/main.rs:4:4
|
3 | let result = first_word(&s);
| -- immutable borrow occurs here
4 | s.clear();
| ^^^^^^^^^ mutable borrow occurs here
5 | println!("{:#?}",result);
| ------ immutable borrow later used here
Let's decompose:
// Let's build a string, which basically is a growable array of chars
let mut s = String::from("Hello world");
// now make result a slice over that string, that is a reference
// to a part of the underlying chars
let result = first_word(&s);
// now let's remove the content of the string (which of course removes
// what the slice was referring to)
s.clear();
// and let's... print it ?
println!("{:#?}", result);
Hopefully the borrow checker prevents you from doing this with this exact error:
cannot borrow s as mutable because it is also borrowed as immutable
And if you've understood this, the solution should be obvious: don't make result a window over another string but a string by itself, having its own content: change the second line to
let result = first_word(&s).to_string();
Now you can clear the source string and keep the first word. Of course to_string() isn't a costless operation so you might want to try keep the source string around in real applications.
The key thing here is lifetimes. By default lifetimes argument for functions with one input reference and output reference are the same (liftime elision). So compiler implicitly changes the code following way:
fn first_word<'a>(s: &'a String) -> &'a str { // note 'a here
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
That means that the result borrows the input argument. You can explicitly make lifetimes different and eliminate error in the main but in this case first_word will not compile:
fn first_word1<'a, 'b>(s: &'a String) -> &'b str {
let bytes = s.as_bytes();
for (i, &item) in bytes.iter().enumerate() {
if item == b' ' {
return &s[0..i];
}
}
&s[..]
}
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
--> src/main.rs:7:21
|
7 | return &s[0..i];
| ^^^^^^^
|
note: first, the lifetime cannot outlive the lifetime 'a as defined on the function body

What's the difference between var and _var in 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.

Resources