rust


How does adding braces to a variable prevent it from being borrowed (owned?) by a match? [duplicate]


I'm trying to navigate a recursive data structure iteratively in order to insert elements at a certain position. To my limited understanding, this means taking a mutable reference to the root of the structure and successively replacing it by a reference to its follower:
type Link = Option<Box<Node>>;
struct Node {
next: Link
}
struct Recursive {
root: Link
}
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
while let Some(ref mut node) = *anchor {
anchor = &mut node.next;
}
anchor
}
}
(Rust playground link)
However, this fails:
error[E0499]: cannot borrow `anchor.0` as mutable more than once at a time
--> src/main.rs:14:24
|
14 | while let Some(ref mut node) = *anchor {
| ^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first mutable borrow occurs here
...
18 | }
| - first borrow ends here
error[E0506]: cannot assign to `anchor` because it is borrowed
--> src/main.rs:15:13
|
14 | while let Some(ref mut node) = *anchor {
| ------------ borrow of `anchor` occurs here
15 | anchor = &mut node.next;
| ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `anchor` occurs here
error[E0499]: cannot borrow `*anchor` as mutable more than once at a time
--> src/main.rs:17:9
|
14 | while let Some(ref mut node) = *anchor {
| ------------ first mutable borrow occurs here
...
17 | anchor
| ^^^^^^ second mutable borrow occurs here
18 | }
| - first borrow ends here
This makes sense as both anchor and node refer to the same structure, but I actually don't care about anchor any more after destructuring it.
How could back() be implemented correctly using safe Rust?
It is possible... but I wish I had a more elegant solution.
The trick is NOT to borrow from anchor, and therefore to juggle between two accumulators:
one holding the reference to the current node
the other being assigned the reference to the next node
This leads me to:
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
loop {
let tmp = anchor;
if let Some(ref mut node) = *tmp {
anchor = &mut node.next;
} else {
anchor = tmp;
break;
}
}
anchor
}
}
Not exactly pretty, but this something the borrow checker can get behind so ¯\_(ツ)_/¯.
#ker has improved on this by creating an unnamed temporary:
impl Recursive {
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
loop {
match {anchor} {
&mut Some(ref mut node) => anchor = &mut node.next,
other => return other,
}
}
}
}
The trick here is that using {anchor} moves the content of anchor into an unnamed temporary on which the match executes. Therefore, in the match block we are not borrowing from anchor but from the temporary, leaving us free to modify anchor. See the related blog post Stuff the Identity Function Does (in Rust).
You can use recursion to satisfy the borrow checker. This has the disadvantage of creating a stack frame for every item in your list. If your list is long, this will definitely run into a stack overflow. LLVM will optimize the Node::back method into a loop (see the LLVM IR generated on the playground)
impl Node {
fn back(&mut self) -> &mut Link {
match self.next {
Some(ref mut node) => node.back(),
None => &mut self.next,
}
}
}
impl Recursive {
fn back(&mut self) -> Option<&mut Link> {
self.root.as_mut().map(|node| node.back())
}
}
It works:
fn back(&mut self) -> &mut Link {
let mut anchor = &mut self.root;
while anchor.is_some(){
anchor = &mut {anchor}.as_mut().unwrap().next;
}
anchor
}

Related Links

Implementing a trait for a trait
Why would I use divergent functions?
Source trait is inaccessible
How to look up a method within the compiler given the type and a name?
How can I use shared logic from different files?
How do I debug macros?
Iterator over elements around specific index in Vec<Vec<Object>>
Return Traits from function
Lifetime for a From trait implementation
Object safety and trait inheritance [duplicate]
How do I specify that a function takes a HashMap?
Cannot implement quickchecks Arbitrary for my own type - “source trait is private”
Returning the T borrowed from RefCell<T>
Trait implementing Sized
Are unique object ids tracked and can we print them?
How can I specify lifetimes in associated types?

Categories

HOME
cocoapods
flask
artificial-intelligence
writefile
embedded-resource
website
apk
elisp
greasemonkey
ontology
dji-sdk
google-search-console
azure-graph-api
fasm
match
cqrs
erd
cname
trace32
phonegap-build
uima
wsf
libgit2
android-permissions
workday
dashdb
multi-upload
acl
software-packaging
dragula
prompt
webviewclient
openbravo
running-object-table
amazon-cloudtrail
location-services
publishing
xcrun
epplus
microsoft-certifications
mongoengine
cloveretl
autoencoder
jfxtras
formsauthenticationticket
love2d
stat
netapp
react-intl
flume-twitter
punctuation
embedded-v8
maven-jaxb2-plugin
nslayoutconstraint
1010
emacs25
maatwebsite-excel
cocoa-bindings
multi-touch
tablespace
wininet
oci
fragmentstatepageradapter
yii2-model
wicked-pdf
wepay
enunciate
textpattern
gql
swagger-maven-plugin
clarion
shell-extensions
hp-idol-ondemand
vs-unit-testing-framework
zend-mail
inequality
producer
windows-rt
aho-corasick
android-2.3-gingerbread
rpg
two.js
nosql-aggregation
quickgraph
jacob
background-thread
office-app
linkbutton
gamesalad
java.lang.class
trialware
affinetransform
mmc3
cewolf
jmenu
bll
django-pagination
webresponse
anonymous-types
android-2.1-eclair
explicit
icicles
reliability
principles
self-tracking-entities
zend-test
dm
icon-language
rootkit

Resources

Encrypt Message