"borrow of moved value" after calling Rust struct function [duplicate] - rust

This is the code I am trying to execute:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
if arg1.is_none() {
return 0;
}
let integer = arg1.unwrap();
*integer
}
fn main() {
let integer = 42;
my_fn(&Some(Box::new(integer)));
}
(on the Rust playground)
I get the following error in previous versions of Rust:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:5:19
|
5 | let integer = arg1.unwrap();
| ^^^^ cannot move out of borrowed content
And in more modern versions:
error[E0507]: cannot move out of `*arg1` which is behind a shared reference
--> src/main.rs:5:19
|
5 | let integer = arg1.unwrap();
| ^^^^
| |
| move occurs because `*arg1` has type `std::option::Option<std::boxed::Box<i32>>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `arg1.as_ref()`
I see there is already a lot of documentation about borrow checker issues, but after reading it, I still can't figure out the problem.
Why is this an error and how do I solve it?

Option::unwrap() consumes the option, that is, it accepts the option by value. However, you don't have a value, you only have a reference to it. That's what the error is about.
Your code should idiomatically be written like this:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
match arg1 {
Some(b) => **b,
None => 0,
}
}
fn main() {
let integer = 42;
my_fn(&Some(Box::new(integer)));
}
(on the Rust playground)
Or you can use Option combinators like Option::as_ref or Option::as_mut paired with Option::map_or, as Shepmaster has suggested:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
arg1.as_ref().map_or(0, |n| **n)
}
This code uses the fact that i32 is automatically copyable. If the type inside the Box weren't Copy, then you wouldn't be able to obtain the inner value by value at all - you would only be able to clone it or to return a reference, for example, like here:
fn my_fn2(arg1: &Option<Box<i32>>) -> &i32 {
arg1.as_ref().map_or(&0, |n| n)
}
Since you only have an immutable reference to the option, you can only return an immutable reference to its contents. Rust is smart enough to promote the literal 0 into a static value to keep in order to be able to return it in case of absence of the input value.

Since Rust 1.40 there is Option::as_deref, so now you can do:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
*arg1.as_deref().unwrap_or(&0)
}

Related

Best practice for handling partial move issues when working with nested structs [duplicate]

This is the code I am trying to execute:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
if arg1.is_none() {
return 0;
}
let integer = arg1.unwrap();
*integer
}
fn main() {
let integer = 42;
my_fn(&Some(Box::new(integer)));
}
(on the Rust playground)
I get the following error in previous versions of Rust:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:5:19
|
5 | let integer = arg1.unwrap();
| ^^^^ cannot move out of borrowed content
And in more modern versions:
error[E0507]: cannot move out of `*arg1` which is behind a shared reference
--> src/main.rs:5:19
|
5 | let integer = arg1.unwrap();
| ^^^^
| |
| move occurs because `*arg1` has type `std::option::Option<std::boxed::Box<i32>>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `arg1.as_ref()`
I see there is already a lot of documentation about borrow checker issues, but after reading it, I still can't figure out the problem.
Why is this an error and how do I solve it?
Option::unwrap() consumes the option, that is, it accepts the option by value. However, you don't have a value, you only have a reference to it. That's what the error is about.
Your code should idiomatically be written like this:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
match arg1 {
Some(b) => **b,
None => 0,
}
}
fn main() {
let integer = 42;
my_fn(&Some(Box::new(integer)));
}
(on the Rust playground)
Or you can use Option combinators like Option::as_ref or Option::as_mut paired with Option::map_or, as Shepmaster has suggested:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
arg1.as_ref().map_or(0, |n| **n)
}
This code uses the fact that i32 is automatically copyable. If the type inside the Box weren't Copy, then you wouldn't be able to obtain the inner value by value at all - you would only be able to clone it or to return a reference, for example, like here:
fn my_fn2(arg1: &Option<Box<i32>>) -> &i32 {
arg1.as_ref().map_or(&0, |n| n)
}
Since you only have an immutable reference to the option, you can only return an immutable reference to its contents. Rust is smart enough to promote the literal 0 into a static value to keep in order to be able to return it in case of absence of the input value.
Since Rust 1.40 there is Option::as_deref, so now you can do:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
*arg1.as_deref().unwrap_or(&0)
}

How do I mutate a variable from inside a rust closure

I'm trying to implement an EventListener like interface in rust. I have a trait that takes a callback, the callback should mutate a variable from the scope it was defined in. But I get an error saying the borrowed value does not live long enough.
pub struct Target<T> {
funcs: Vec<Box<dyn FnMut(T) -> ()>>,
}
impl<T: Clone + 'static> Target<T> {
pub fn new() -> Target<T> {
return Target { funcs: Vec::new() };
}
pub fn add_listener(&mut self, func: Box<dyn FnMut(T) -> ()>) -> () {
self.funcs.push(Box::new(func));
}
pub fn trigger(&mut self, x: T) {
for callback in &mut self.funcs {
callback(x.clone());
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trigger_mutation() {
let mut a = 0;
let mut t: Target<i32> = Target::new();
t.add_listener(Box::new(|x: i32| {
println!("{}", x);
a = x;
}));
t.trigger(42);
let b = a.clone();
assert_eq!(b, 42);
}
}
I run it and get this:
$ cargo test -- --nocapture
Compiling luma-connector v0.1.0 (/home/blake/git/connector)
error[E0597]: `a` does not live long enough
--> src/target.rs:32:13
|
30 | t.add_listener(Box::new(|x: i32| {
| - -------- value captured here
| ________________________|
| |
31 | | println!("{}", x);
32 | | a = x + 1;
| | ^ borrowed value does not live long enough
33 | | }));
| |__________- cast requires that `a` is borrowed for `'static`
...
37 | }
| - `a` dropped here while still borrowed
But I get an error saying the borrowed value does not live long enough.
Well yes, your typing of Target implies nothing about scoping, so as far as the Rust typesystem is concerned, the closure could just fly into space unbouded by time (e.g. add_listener could pass it to a separate thread), therefore outlive trigger_mutation, which means a does not live long enough.
There are two ways to resolve this issue:
Use Arc/Rc with interior mutability (resp. Mutex and RefCell) in order to relax the lifetime of a: Arc version[0], Rc version, this is probably the simplest, and the least restrictive on Target, though it comes at a runtime cost.
Alternatively you can "scope" Target to tell Rust that it doesn't escape, therefore everything's perfectly kosher. I'm not sure it's the best way (hopefully somebody else can contribute that information) but bounding the FnMuts on a lifetime will allow rustc to reason about this: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=e67a4ab0faa8cc5d01c75293623c9fb4
This is basically free at runtime, but it means Target can't really escape its function.
So the former is probably what you want, the latter seems not super-useful for an events / notification system, but YMMV.
[0] an Atomic* would also work for the Arc version and be a bit easier & cheaper than a mutex, though it probably isn't very relevant for a test case.

Why do some while-let assignments inside a loop fail to compile with "cannot borrow as mutable more than once at a time"? [duplicate]

Suppose I have several structures like in the following example, and in the next() method I need to pull the next event using a user-provided buffer, but if this event is a comment, and ignore comments flag is set to true, I need to pull the next event again:
struct Parser {
ignore_comments: bool,
}
enum XmlEvent<'buf> {
Comment(&'buf str),
Other(&'buf str),
}
impl Parser {
fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
let result = loop {
buffer.clear();
let temp_event = self.parse_outside_tag(buffer);
match temp_event {
XmlEvent::Comment(_) if self.ignore_comments => {}
_ => break temp_event,
}
};
result
}
fn parse_outside_tag<'buf>(&mut self, _buffer: &'buf mut String) -> XmlEvent<'buf> {
unimplemented!()
}
}
This code, however, gives a double borrow error, even when I have #![feature(nll)] enabled:
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:14:13
|
14 | buffer.clear();
| ^^^^^^ second mutable borrow occurs here
15 |
16 | let temp_event = self.parse_outside_tag(buffer);
| ------ first mutable borrow occurs here
|
note: borrowed value must be valid for the lifetime 'buf as defined on the method body at 12:5...
--> src/main.rs:12:5
|
12 | fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:16:53
|
16 | let temp_event = self.parse_outside_tag(buffer);
| ^^^^^^ mutable borrow starts here in previous iteration of loop
|
note: borrowed value must be valid for the lifetime 'buf as defined on the method body at 12:5...
--> src/main.rs:12:5
|
12 | fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 2 previous errors
I can (approximately at least) understand why an error could happen here with the NLL feature turned off, but I don't understand why it happens with NLL.
Anyway, my end goal is to implement this without flags, so I also tried doing this (it is recursive, which is really unfortunate, but all non-recursive versions I came up with could not possibly work without NLL):
fn next<'buf>(&mut self, buffer: &'buf mut String) -> XmlEvent<'buf> {
buffer.clear();
{
let temp_event = self.parse_outside_tag(buffer);
match temp_event {
XmlEvent::Comment(_) if self.ignore_comments => {}
_ => return temp_event,
}
}
self.next(buffer)
}
Here I tried to confine the borrow inside a lexical block, and nothing from this block leaks to the outside. However, I'm still getting an error:
error[E0499]: cannot borrow `*buffer` as mutable more than once at a time
--> src/main.rs:23:19
|
15 | let temp_event = self.parse_outside_tag(buffer);
| ------ first mutable borrow occurs here
...
23 | self.next(buffer)
| ^^^^^^ second mutable borrow occurs here
24 | }
| - first borrow ends here
error: aborting due to previous error
And again, NLL does not fix it.
It has been a long time since I encountered a borrow checking error which I don't understand, so I'm hoping it is actually something simple which I'm overlooking for some reason :)
I really suspect that the root cause is somehow connected with the explicit 'buf lifetime (in particular, errors with the NLL flag turned on have these notes about it), but I can't understand what exactly is wrong here.
This is a limitation of the current implementation of non-lexical lifetimes This can be shown with this reduced case:
fn next<'buf>(buffer: &'buf mut String) -> &'buf str {
loop {
let event = parse(buffer);
if true {
return event;
}
}
}
fn parse<'buf>(_buffer: &'buf mut String) -> &'buf str {
unimplemented!()
}
fn main() {}
This limitation prevents NLL case #3: conditional control flow across functions
In compiler developer terms, the current implementation of non-lexical lifetimes is "location insensitive". Location sensitivity was originally available but it was disabled in the name of performance.
I asked Niko Matsakis about this code:
In the context of your example: the value event only has to have the lifetime 'buf conditionally — at the return point which may or may not execute. But when we are "location insensitive", we just track the lifetime that event must have anywhere, without considering where that lifetime must hold. In this case, that means we make it hold everywhere, which is why you get a compilation failure.
One subtle thing is that the current analysis is location sensitive in one respect — where the borrow takes place. The length of the borrow is not.
The good news is that adding this concept of location sensitivity back is seen as an enhancement to the implementation of non-lexical lifetimes. The bad news:
That may or may not be before the [Rust 2018] edition.
(Note: it did not make it into the initial release of Rust 2018)
This hinges on a (even newer!) underlying implementation of non-lexical lifetimes that improves the performance. You can opt-in to this half-implemented version using -Z polonius:
rustc +nightly -Zpolonius --edition=2018 example.rs
RUSTFLAGS="-Zpolonius" cargo +nightly build
Because this is across functions, you can sometimes work around this by inlining the function.
I posted a question (A borrow checker problem with a loop and non-lexical lifetimes) that was answered by the answer of this question.
I'll document here a workaround that also answers the question. Let's say you have code like this, that only compiles with Polonius:
struct Inner;
enum State<'a> {
One,
Two(&'a ()),
}
fn get<'s>(_inner: &'s mut Inner) -> State<'s> {
unimplemented!()
}
struct Outer {
inner: Inner,
}
impl Outer {
pub fn read<'s>(&'s mut self) -> &'s () {
loop {
match get(&mut self.inner) {
State::One => (), // In this case nothing happens, the borrow should end and the loop should continue
State::Two(a) => return a, // self.inner ought to be borrowed for 's, that's just to be expected
}
}
}
}
As it was said in the another answer:
One subtle thing is that the current analysis is location sensitive in one respect — where the borrow takes place. The length of the borrow is not.
Indeed, borrowing the needed reference again inside the conditional branch makes it compile! Of course, this makes the assumption that get is referentially transparent, so your mileage may vary, but borrowing again seems like an easy enough workaround.
struct Inner;
enum State<'a> {
One,
Two(&'a ()),
}
fn get<'s>(_inner: &'s mut Inner) -> State<'s> {
unimplemented!()
}
struct Outer {
inner: Inner,
}
impl Outer {
pub fn read<'s>(&'s mut self) -> &'s () {
loop {
match get(&mut self.inner) {
State::One => (), // In this case nothing happens, the borrow should end and the loop should continue
State::Two(a) => {
return match get(&mut self.inner) { // Borrowing again compiles!
State::Two(a) => a,
_ => unreachable!(),
}
}, // self.inner ought to be borrowed for 's, that's just to be expected
}
}
}
}
fn main() {
println!("Hello, world!");
}

Accessing struct member that is inside Option of a Rc in Rust [duplicate]

This is the code I am trying to execute:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
if arg1.is_none() {
return 0;
}
let integer = arg1.unwrap();
*integer
}
fn main() {
let integer = 42;
my_fn(&Some(Box::new(integer)));
}
(on the Rust playground)
I get the following error in previous versions of Rust:
error[E0507]: cannot move out of borrowed content
--> src/main.rs:5:19
|
5 | let integer = arg1.unwrap();
| ^^^^ cannot move out of borrowed content
And in more modern versions:
error[E0507]: cannot move out of `*arg1` which is behind a shared reference
--> src/main.rs:5:19
|
5 | let integer = arg1.unwrap();
| ^^^^
| |
| move occurs because `*arg1` has type `std::option::Option<std::boxed::Box<i32>>`, which does not implement the `Copy` trait
| help: consider borrowing the `Option`'s content: `arg1.as_ref()`
I see there is already a lot of documentation about borrow checker issues, but after reading it, I still can't figure out the problem.
Why is this an error and how do I solve it?
Option::unwrap() consumes the option, that is, it accepts the option by value. However, you don't have a value, you only have a reference to it. That's what the error is about.
Your code should idiomatically be written like this:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
match arg1 {
Some(b) => **b,
None => 0,
}
}
fn main() {
let integer = 42;
my_fn(&Some(Box::new(integer)));
}
(on the Rust playground)
Or you can use Option combinators like Option::as_ref or Option::as_mut paired with Option::map_or, as Shepmaster has suggested:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
arg1.as_ref().map_or(0, |n| **n)
}
This code uses the fact that i32 is automatically copyable. If the type inside the Box weren't Copy, then you wouldn't be able to obtain the inner value by value at all - you would only be able to clone it or to return a reference, for example, like here:
fn my_fn2(arg1: &Option<Box<i32>>) -> &i32 {
arg1.as_ref().map_or(&0, |n| n)
}
Since you only have an immutable reference to the option, you can only return an immutable reference to its contents. Rust is smart enough to promote the literal 0 into a static value to keep in order to be able to return it in case of absence of the input value.
Since Rust 1.40 there is Option::as_deref, so now you can do:
fn my_fn(arg1: &Option<Box<i32>>) -> i32 {
*arg1.as_deref().unwrap_or(&0)
}

How do I pass a mutable vector as a function parameter in Rust?

I am implementing a small program that evaluates the Collatz conjecture. As part of this, I have a function that I call recursively that I want to store the current number being evaluated, determine if it is a odd or even (or terminate if it's just a 1), perform that branch of the conjecture and then call itself with the new number.
To do this, I wanted to pass a vector into this function and push the current number onto that vector, but I am having a tough time understanding how to pass a mutable vector reference.
Here is the code that I have:
fn evaluate_conjecture(number_to_be_evaluated: u64, mut intermediate_results: &Vec<u64>) -> u64 {
intermediate_results.push(number_to_be_evaluated);
if number_to_be_evaluated == 1 {
0
} else if number_to_be_evaluated % 2 == 1 {
let odd_step_result = perform_odd_conjecture_step(number_to_be_evaluated);
evaluate_conjecture(odd_step_result, intermediate_results) + 1
} else {
let even_step_result = perform_even_conjecture_step(number_to_be_evaluated);
evaluate_conjecture(even_step_result, intermediate_results) + 1
}
}
fn perform_odd_conjecture_step(_: u64) -> u64 {
unimplemented!()
}
fn perform_even_conjecture_step(_: u64) -> u64 {
unimplemented!()
}
and here is the relevant part of my main
fn main() {
let input_number = 42;
let mut _intermediate_results: Vec<u64>;
let number_of_steps = evaluate_conjecture(input_number, &_intermediate_results);
}
Here is the error I am getting
error[E0596]: cannot borrow `*intermediate_results` as mutable, as it is behind a `&` reference
--> src/main.rs:2:5
|
1 | fn evaluate_conjecture(number_to_be_evaluated: u64, mut intermediate_results: &Vec<u64>) -> u64 {
| --------- help: consider changing this to be a mutable reference: `&mut std::vec::Vec<u64>`
2 | intermediate_results.push(number_to_be_evaluated);
| ^^^^^^^^^^^^^^^^^^^^ `intermediate_results` is a `&` reference, so the data it refers to cannot be borrowed as mutable
How do I pass this vector into the function so I can modify it each time the function is called?
&T is an immutable reference.
&mut T is a mutable reference.
Change your &Vec<u64> to &mut Vec<u64> and your &_intermediate_results to &mut _intermediate_results.
This is a thing which is fairly well documented; I suggest you read the documentation if you haven’t — it explains quite a lot. There's a section specifically about mutable references.

Resources