pub fn delete_duplicates(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
let mut head = head;
let mut cur = head.as_mut();
while cur.is_some() && cur.as_ref().unwrap().next.is_some() {
if cur.as_ref().unwrap().val == cur.as_ref().unwrap().next.as_ref().unwrap().val {
//let next = cur.unwrap().next.as_mut().unwrap().next.take(); (1) Error!
let next = cur.as_mut().unwrap().next.as_mut().unwrap().next.take(); // (2) Ok
cur.as_mut().unwrap().next = next;
}
else {
//cur = cur.as_ref().unwrap().next.as_mut(); (3) Error!
cur = cur.unwrap().next.as_mut(); // (4) Ok
}
}
head
}
The code above deletes duplicates inside a custom single linked list. (e.g. [1,1,2] -> [1,2])
Using (2) and (4) compiles and does what the program is supposed to do.
(1) and (3) generate compiler error and I just can't grasp what is happening here.
(1) Why do we need as_mut()? I believe cur is already mutable.
(3) Why can't I use as_ref() when assigning a value to lvalue?
(4) Isn't this consuming the Options as we proceed?
I have created a reproducible playground. Other folks, please use it to help and correct me if my answer is wrong.
For (1), when you call cur.unwrap(), the value (Option<&mut Box<ListNode>>) got moved from cur. but when you call cur.as_mut(), it gave you a Option<&mut &mut Box<ListNode>>, and unwrapping it doesn't move cur's value. I created a small playground code snippet to illustrate this.
For (3), it has two errors.
when you call cur.as_ref(), the value is behind a &, so you cannot access its value but then borrowed it as mutable again when you call as_mut()
if you replace the as_ref() call in (3) with a as_mut() call, you will see only the other error.
Line 28, Char 17: cannot assign to `cur` because it is borrowed (solution.rs)
|
28 | cur = cur.as_mut().unwrap().next.as_mut();
| ^^^^^^---^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | borrow of `cur` occurs here
| assignment to borrowed `cur` occurs here
| borrow later used here
error: aborting due to previous error
You cannot first borrow cur's value, reassign cur with a new value, then use the borrowed value. Playground to illustrate this.
For (4), yes, it consumes cur's value, which is a Option<&mut Box<ListNode>>, not Option<Box<ListNode>>, so it is OK.
Related
I'm learning Rust and I have this code while following a tutorial. All that this set of code does is loop through the numbers and add up the total.
enum Shot {
Bullseye,
Hit(f64),
Miss,
}
impl Shot {
fn points(self) -> i32 {
match self {
Shot::Bullseye => 5,
Shot::Hit(x) if x < 3.0 => 2,
Shot::Hit(x) => 1,
_ => 0,
}
}
}
fn main() {
let mut shots: Vec<Shot> = Vec::new();
shots.push(Shot::Bullseye);
shots.push(Shot::Hit(5.0));
shots.push(Shot::Miss);
let mut total = 0;
for shot in shots.iter() {
let points = shot.points();
total += points
}
println!("Total: {}", total);
}
However, when I run this, I get the following error:
error[E0507]: cannot move out of `*shot` which is behind a shared reference
|
68 | let points = shot.points();
| ^^^^^--------
| | |
| | `*shot` moved due to this method call
| move occurs because `*shot` has type `Shot`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves `*shot`
--> src/main.rs:21:15
|
21 | fn points(self) -> i32 {
| ^^^^
Strangely, if I change it to this, everything compiles without error:
for shot in shots {
let points = shot.points();
total += points
}
Why does it work when I remove the iterator? And yet the loop works without the iterator?
I tried deciphering the error message but still couldn't understand what is happening. In this case, I believe shot is a reference. I'm calling the shot.points() function which returns an i32 value which is owned by the variable points. Yet, the error mentioned about shot being moved due to the call on the shot.points() function?
What does the error really mean and why is that happening?
Let's try and get the actual type of shot inside the loop:
for shot in shots.iter() {
let foo: () = shot;
}
Playground
The error message tells us that shot has type &Shot. In other words, it's a shared reference to Shot. But points is defined as fn points (self) -> i32 which means that it expects an owned value, so you can't call shot.points() on a reference. As pointed out by others the fix is easy: simply change points to take a reference, i.e. fn points (&self) -> i32 (playground).
Now why does it work if we remove the .iter()? Look what happens to the type in that case:
for shot in shots {
let foo: () = shot;
}
Playground
Now shot has type Shot, no reference. This is because for shot in shots is actually equivalent to for shot in shots.into_iter(), which consumes shots and iterates over owned values. The consequence is that you can non longer use it after the loop:
for shot in shots {
}
println!("{:?}", shots);
doesn't work:
error[E0382]: borrow of moved value: `shots`
--> src/main.rs:32:22
|
20 | let mut shots: Vec<Shot> = Vec::new();
| --------- move occurs because `shots` has type `Vec<Shot>`, which does not implement the `Copy` trait
...
28 | for shot in shots {
| ----- `shots` moved due to this implicit call to `.into_iter()`
...
32 | println!("{:?}", shots);
| ^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `shots`
--> /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/iter/traits/collect.rs:262:18
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider iterating over a slice of the `Vec<Shot>`'s content to avoid moving into the `for` loop
|
28 | for shot in &shots {
| +
The function points takes ownership of shot, so on the next iteration it can't do that again.
Giving what you do with shot (just reading), you may use an immutable reference to solve the issue:
fn points(&self) -> i32 {
You would also need to dereference x
Shot::Hit(x) if *x < 3.0 => 2,
Rust playground link
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
fn main() {
let f = File::open("test.txt").expect("Can't open");
let mut b = BufReader::new(f);
let v = b.fill_buf().unwrap();
println!("v: {:?}", v);
b.consume(v.len());
}
will not compile, the error is
error[E0499]: cannot borrow `b` as mutable more than once at a time
--> src/main.rs:10:5
|
7 | let v = b.fill_buf().unwrap();
| ------------ first mutable borrow occurs here
...
10 | b.consume(v.len());
| ^^^^^^^^^^-------^
| | |
| | first borrow later used here
| second mutable borrow occurs here
Changing the last lines to:
let len = v.len();
b.consume(len);
And all is ok.
I fail to understand why the first example is borrowing something twice, and why storing the length in a variable and passing that variable to b.consume() is ok - could someone explain why the 2. variant is ok, and the first is not ?
When you run into this kind of issue, it can help to desugar things a bit. As you may know, method syntax is syntax sugar for an associated function call:
b.consume(v.len());
// desugars to
BufRead::consume(&mut b, [_]::len(v));
Argument expressions are generally evaluated left-to-right, so we try to get a new mutable reference to b before we release the reference we're holding in v. There are some cases where the compiler can recognize and automatically avoid this issue, but this does not seem to be one of those cases.
You may ask "Why does it say second mutable reference? v is an immutable reference!" Well, the lifetime of the reference in v is tied to the lifetime of the mutable reference when you call b.fill_buf(). So the compiler thinks that the mutable reference to b must remain valid until v is released.
The reason the fix works is because it flips the order of the arguments, evaluating v.len() first, and releasing that first reference.
Please help me to compile my code attached bellow. The compiler says that following 2 patterns depending on which lines I comment out.
The program reads a &str which is a simple "svg path command" like code then parses it. The pasted code has been simplified for simplicity. It uses Regex to split the input string into lines then study each line in the main for loop. Each loop pushes the parse result onto a vector. Finally the function returns the vector.
Basically the compiler says returning the vector is not allowed because it refers local variable. Though I don't have any workaround.
error[E0597]: `cmd` does not live long enough
--> src/main.rs:24:25
|
24 | codeV = re.captures(cmd.as_str());
| ----- ^^^ borrowed value does not live long enough
| |
| borrow might be used here, when `codeV` is dropped and runs the destructor for type `Option<regex::Captures<'_>>`
...
30 | }
| - `cmd` dropped here while still borrowed
|
= note: values in a scope are dropped in the opposite order they are defined
error[E0515]: cannot return value referencing local variable `cmd`
--> src/main.rs:31:1
|
24 | codeV = re.captures(cmd.as_str());
| --- `cmd` is borrowed here
...
31 | V //Error
| ^ returns a value referencing data owned by the current function
Playground
use regex::Regex;
pub fn parse(path:&str) {//->Vec<Option<regex::Captures<>>> //Error
let reg_n=Regex::new(r"\n").unwrap();
let path=reg_n.replace_all("\n"," ");
let reg_cmd=Regex::new(r"(?P<cmd>[mlhv])").unwrap();
let path=reg_cmd.replace_all(&path,"\n${cmd}");
let cmdV=reg_n.split(&path);
//let cmdV:Vec<&str> = reg.split(path).map(|x|x).collect();
let mut V:Vec<Option<regex::Captures<>>>=vec![];
let mut codeV:Option<regex::Captures<>>=None;
let mut count=0;
for cmd_f in cmdV{//This loop block has been simplified.
count+=1;
if count==1{continue;}
let mut cmd="".to_string();
cmd=cmd_f.to_string();
cmd=cmd.replace(" ","");
let re = Regex::new(r"\{(?P<code>[^\{^\}]{0,})\}").unwrap();
codeV = re.captures(cmd.as_str());
//cmd= re.replace_all(cmd.as_str(),"").to_string();
let cmd_0=cmd.chars().nth(0).unwrap();
//cmd.remove(0);
//V.push(codeV); //Compile error
V.push(None); //OK
}
//V
}
fn main() {
parse("m {abcd} l {efgh}");
}
Though I don't have any workaround.
regex's captures refer to the string they matched for efficiency. This means they can't outlive that string, as the match groups are essentially just offsets into that string.
Since the strings you match are created in the loop body, this means captures can't escape the loop body.
Aside from not creating strings in the loop body (or even the function), the solution / workaround is to convert your capture groups to owned data and store that: instead of trying to return a vector of captures, extract from the capture the data you actually want, convert it to an owned String (or tuple thereof, or whatever), and push that onto your vector.
e.g. https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=0107333e30f831a418d75b280e9e2f31
you can use cmd.clone().as_str() if you not sure the value has borrowed or no
I'm trying to insert a value into a HashMap based on another value in the same HashMap, like so:
use std::collections::HashMap;
fn main() {
let mut some_map = HashMap::new();
some_map.insert("a", 1);
let some_val = some_map.get("a").unwrap();
if *some_val != 2 {
some_map.insert("b", *some_val);
}
}
which gives this warning:
warning: cannot borrow `some_map` as mutable because it is also borrowed as immutable
--> src/main.rs:10:9
|
7 | let some_val = some_map.get("a").unwrap();
| -------- immutable borrow occurs here
...
10 | some_map.insert("b", *some_val);
| ^^^^^^^^ --------- immutable borrow later used here
| |
| mutable borrow occurs here
|
= note: `#[warn(mutable_borrow_reservation_conflict)]` on by default
= warning: this borrowing pattern was not meant to be accepted, and may become a hard error in the future
= note: for more information, see issue #59159 <https://github.com/rust-lang/rust/issues/59159>
If I were instead trying to update an existing value, I could use interior mutation and RefCell, as described here.
If I were trying to insert or update a value based on itself, I could use the entry API, as described here.
I could work around the issue with cloning, but I would prefer to avoid that since the retrieved value in my actual code is somewhat complex. Will this require unsafe code?
EDIT
Since previous answer is simply false and doesn't answer the question at all, there's code which doesn't show any warning (playground)
Now it's a hashmap with Rc<_> values, and val_rc contains only a reference counter on actual data (number 1 in this case). Since it's just a counter, there's no cost of cloning it. Note though, that there's only one copy of a number exists, so if you modify a value of some_map["a"], then some_map["b"] is modified aswell, since they refer to a single piece of memory. Also note, that 1 lives on stack, so you better consider turn it into Rc<Box<_>> if you plan to add many heavy objects.
use std::collections::HashMap;
use std::rc::Rc;
fn main() {
let mut some_map = HashMap::new();
some_map.insert("a", Rc::new(1));
let val_rc = Rc::clone(some_map.get("a").unwrap());
if *val_rc != 2 {
some_map.insert("b", val_rc);
}
}
Previous version of answer
Hard to tell what exactly you're looking for, but in this particular case, if you only need to check the value, then destroy the borrowed value, before you update the hashmap. A dirty and ugly code would be like this:
fn main() {
let mut some_map = HashMap::new();
some_map.insert("a", 1);
let is_ok = false;
{
let some_val = some_map.get("a").unwrap();
is_ok = *some_val != 2;
}
if is_ok {
some_map.insert("b", *some_val);
}
}
I'm learning Rust and tried coding a doubly-linked list. However, I'm stuck already at a typical iterative traversal implementation. I'm getting the impression that the borrow checker / drop checker is too strict and cannot infer the correct lifetime for the borrow when it crosses the function boundary from RefCell. I need to repeatedly set a variable binding (curr in this case) to the borrow of its current contents:
use std::cell::RefCell;
use std::rc::Rc;
pub struct LinkedList<T> {
head: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
struct LinkedNode<T> {
value: T,
next: Option<Rc<RefCell<LinkedNode<T>>>>,
// ...
}
impl<T> LinkedList<T> {
pub fn insert(&mut self, value: T, idx: usize) -> &mut LinkedList<T> {
// ... some logic ...
// This is the traversal that fails to compile.
let mut curr = self.head.as_ref().unwrap();
for _ in 1..idx {
curr = curr.borrow().next.as_ref().unwrap()
}
// I want to use curr here.
// ...
unimplemented!()
}
}
The compiler complains:
Without NLL
error[E0597]: borrowed value does not live long enough
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^ temporary value does not live long enough
23 | }
| - temporary value dropped here while still borrowed
...
28 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
With NLL
error[E0716]: temporary value dropped while borrowed
--> src/lib.rs:22:20
|
22 | curr = curr.borrow().next.as_ref().unwrap()
| ^^^^^^^^^^^^^
| |
| creates a temporary which is freed while still in use
| a temporary with access to the borrow is created here ...
23 | }
| -
| |
| temporary value is freed at the end of this statement
| ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, LinkedNode<T>>`
|
= note: consider using a `let` binding to create a longer lived value
= note: The temporary is part of an expression at the end of a block. Consider adding semicolon after the expression so its temporaries are dropped sooner, before the local variables declared by the block are dropped.
I would really appreciate a iterative solution (non-recursive) to this problem.
You can clone Rc to avoid lifetime issues:
let mut curr = self.head.as_ref().unwrap().clone();
for _ in 1..idx {
let t = curr.borrow().next.as_ref().unwrap().clone();
curr = t;
}
Here's a smaller reproduction that I believe shows the same problem:
use std::cell::RefCell;
fn main() {
let foo = RefCell::new(Some(42));
let x = foo.borrow().as_ref().unwrap();
}
As I read it:
foo.borrow() returns a cell::Ref, a type of smart pointer. In this case, the smart pointer acts like an &Option<i32>.
as_ref() creates an Option<&i32> where the inner reference has the same lifetime as the smart pointer.
The Option is discarded, yielding only an &i32, still with a lifetime of the smart pointer.
Notably, the smart pointer Ref only lasts for the statement, but the code attempts to return a reference into the Ref that would outlive the statement.
Generally, the solution would be to do something like this:
let foo_borrow = foo.borrow();
let x = foo_borrow.as_ref().unwrap();
This keeps the smart pointer around longer, allowing the lifetime of the reference to be valid for as long as foo_borrow (representing the borrow itself) exists.
In the case of a loop, there's not much you can do, as you essentially want to borrow every previous node until you get to the next one.