rust


Rust borrow checker prevents reuse after end of scope [duplicate]


I've got a persistent compile error where Rust complains that I have an immutable borrow while I'm trying to mutably borrow, but the immutable borrow is from another scope, and I'm not bringing anything across from it.
Basically I have some code that checks for a value in a map, and if it's present, returns it, otherwise it needs to mutate the map in various ways. The problem is that I can't seem to find a way to get Rust let me do both, even though the two operations are totally separate.
Here's some nonsensical code that follows the same structure as my code and exhibits the problem:
fn do_stuff(map: &mut BTreeMap<i32, i32>, key: i32) -> Option<&i32> {
// extra scope in vain attempt to contain the borrow
{
match map.get(&key) { // borrow immutably
Some(key) => { return Some(key); },
None => (),
}
}
// now I'm DONE with the immutable borrow, but rustc still thinks it's borrowed
map.insert(0, 0); // borrow mutably, which errors
None
}
This errors out with:
error: cannot borrow `*map` as mutable because it is also borrowed as immutable [--explain E0502]
--> <anon>:13:5
5 |> match map.get(&key) {
|> --- immutable borrow occurs here
...
13 |> map.insert(0, 0);
|> ^^^ mutable borrow occurs here
14 |> None
15 |> }
|> - immutable borrow ends here
This doesn't make any sense to me. How does the immutable borrow outlive that scope?! One branch of that match exits the function via return, and the other does nothing and leaves the scope.
I've seen this happen before where I was mistakenly smuggling the borrow out of the scope in some other variable, but that's not the case here!
True, the borrow is escaping the scope via the return statement, but it's ridiculous that that blocks borrowing farther down in the function -- the program cannot possibly return AND keep going! If I return something else there, the error goes away, so I think this is what the borrow checker is getting hung up on. This feels like a bug to me.
Unfortunately, I've been unable to find any way to rewrite this without hitting the same error, so it's a particularly nasty bug if that's the case.
This is a known issue that is very likely to be solved by non-lexical scopes, which is itself predicated on MIR. If it so happens that you are inserting to the same key that you are looking up, I'd encourage you to use the entry API.
You can add a smidgen of inefficiency to work around this for now though:
use std::collections::BTreeMap;
fn do_stuff(map: &mut BTreeMap<i32, i32>, key: i32) -> Option<&i32> {
if map.contains_key(&key) {
return map.get(&key);
}
map.insert(0, 0);
None
}
fn main() {
let mut map = BTreeMap::new();
do_stuff(&mut map, 42);
println!("{:?}", map)
}
Similar cases with a vector instead of a HashMap can be solved by using the index of the element instead of the reference. Like the case above, this can introduce a bit of inefficiency due to the need to check the slice bounds again.
Instead of
fn find_or_create_five<'a>(container: &'a mut Vec<u8>) -> &'a mut u8 {
match container.iter_mut().find(|e| **e == 5) {
Some(element) => element,
None => {
container.push(5);
container.last_mut().unwrap()
}
}
}
You can write:
fn find_or_create_five<'a>(container: &'a mut Vec<u8>) -> &'a mut u8 {
let idx = container.iter().position(|&e| e == 5).unwrap_or_else(|| {
container.push(5);
container.len() - 1
});
&mut container[idx]
}

Related Links

What is the safe way to convert a Vec<T> to a &[T]
How do I shuffle a VecDeque?
Can I use a mutable reference method like a value-passing one?
How to execute Rust code directly on Unix systems? (using the shebang)
Convenient 'Option<Box<Any>>' access when success is assured?
Use a closure inside a thread
How to change the variable from inside Fn closure in Rust?
Create mutual reference for rust [duplicate]
How do I safely use an object while it is mutably borrowed?
Workspace giving two different behaviors in Rust
Restricting object lifetimes in Rust
Project with serde cannot compile
Cannot infer an appropriate lifetime for autoref due to conflicting requirements
How to define a hashmap with contents in 1 line in Rust? [duplicate]
How solve “cannot index a value of type `usize`” error?
Preserve lifetime of an argument in another object [duplicate]

Categories

HOME
google-chrome
android-espresso
class
opencart
yaml
focus
hdfs
openlayers-3
slider
gprs
specifications
log4j2
nexus3
parsley.js
orc
stimulsoft
squirrel-sql
twisted
l20n
raml
activeadmin
sqlplus
pst
exchange-server-2010
react-dnd
tortoisemerge
openbravo
ccavenue
django-import-export
adapter
spring-annotations
sparkle
toad
objectmapper
argv
riotjs
android-canvas
java-stream
bean-validation
char-pointer
xerces-c
pdfnet
aurelia-cli
utf
cloudera-sentry
fiware-wirecloud
optionaldataexception
permission-denied
nomad
webalizer
freshdesk
nivo-slider
ptvs
sesame
dymola
boost-compute
mifos
e
msg
wininet
android-sdcard
bbc-micro
mathnet
gwt-syncproxy
psd
ioctl
m4
phpquery
mixins
modern.ie
swagger-maven-plugin
wicked-gem
nanomsg
phonegap-facebook-plugin
thoughtworks-go
storing-data
siena
category-theory
hotswap
lsa
ldif
jacob
rikulo
axacropdf
oembed
android-dialog
instance-variables
system-information
nsfont
datacontracts
server-variables
play2-mini
botnet
page-curl
nsconnection
bll
bass
tabbarcontroller
fgetc
subtext
suggestbox

Resources

Mobile Apps Dev
Database Users
javascript
java
csharp
php
android
MS Developer
developer works
python
ios
c
html
jquery
RDBMS discuss
Cloud Virtualization
Database Dev&Adm
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App