rust


Why is variable scope dependent on the definition order?


I have a basic (and probably stupid) ownership question. I am trying to create a vector of &str from String values wrapped inside Some(String). I am using an intermediate variable to store the extracted/unwrapped String and it seems I need to define this intermediary variable before the vector in order to satisfy the borrow checker:
Working code:
fn main() {
let a = Some("a".to_string());
let mut val = String::new();
let mut v = Vec::<&str>::new();
if a.is_some() {
val = a.unwrap();
v.push(&val[..]);
}
println!("{:?}", val);
}
Non working code:
fn main() {
let a = Some("a".to_string());
let mut v = Vec::<&str>::new();
let mut val = String::new();
if a.is_some() {
val = a.unwrap();
v.push(&val[..]);
}
println!("{:?}", val);
}
And the compiler errors:
<anon>:9:17: 9:20 error: `val` does not live long enough
<anon>:9 v.push(&val[..]);
^~~
<anon>:4:35: 12:2 note: reference must be valid for the block suffix following statement 1 at 4:34...
<anon>:4 let mut v = Vec::<&str>::new();
<anon>:5 let mut val = String::new();
<anon>:6
<anon>:7 if a.is_some() {
<anon>:8 val = a.unwrap();
<anon>:9 v.push(&val[..]);
...
<anon>:5:32: 12:2 note: ...but borrowed value is only valid for the block suffix following statement 2 at 5:31
<anon>:5 let mut val = String::new();
<anon>:6
<anon>:7 if a.is_some() {
<anon>:8 val = a.unwrap();
<anon>:9 v.push(&val[..]);
<anon>:10 }
...
error: aborting due to previous error
playpen: application terminated with error code 101
The playpen code
The question is: why do I have to define the val variable before the vector v? As I see it, val scope is the same as v scope, or am I missing something?
Bindings are dropped in reverse order of declaration, i.e. the most recently declared thing is destroyed first. Specifically, in the code that doesn't work, the destructor of val runs before the destructor of v. Without careful consideration of what Vec<&str>::drop() does, this is not safe: It could for example try to look at the contents of the string slices it contains, despite the fact that the String from which they derive is already destroyed.
Vec doesn't actually do that, but other legitimate types do something along those lines. Previously it was impossible to safely implement Drop for types that contain lifetimes/borrowed pointers. A relatively recent change makes it safe by introducing these additional restrictions.
Note that if you declare let v, val; or let val, v; and later assign, the two bindings do have the same lifetime, so it's not impossible to have two variables of the same lifetime.

Related Links

Iterate two vectors and the rest of the larger one
How do I implement Clone/Copy for an enum that contains a String?
Modeling embedded hardware in Rust and how to have multiple mutable references cleanly?
Should I borrow or copy my small data types?
Using pointer casting to change the “type” of data in memory [duplicate]
Export function only to module test?
Take slice of certain length known at compile time
Is it possible to deactivate file locking in cargo?
“does not live long enough” error in same function
What ways exist to create containers of several types? [duplicate]
How can I optimize reading a UTF-8 string from a file with a known offset and size?
Create vector of objects implementing a trait in Rust
Using loop variable from “..” loop causes type conversion?
What is RFC 401's coerce_inner useful for?
Rust Borrow checker only complains about borrowing as mutable multiple times when a function that returns a reference with the same lifetime assigned
How can I remove `let _ : () = …`?

Categories

HOME
gaming
devexpress
hid
out-of-memory
histogram
android-emulator
consul
google-play-services
gentelella
elk-stack
iptables
phpmqtt
gtk
hystrix
migrate
xamarin-zebble
fireloop
locationmanager
buffer
smooks
mailgun
bnf
phonegap-build
salt-cloud
significance
dashdb
kaggle
amazon-sns
raima
strophe.js
hevc
bonita
es6-modules
opnet
epplus
listjs
image-optimization
assertions
nsuserdefaults
fastlane
aurelia-cli
1wire
doctrine-extensions
axis
intellij-lombok-plugin
sharpdx
entropy
embedded-v8
sequence-diagram
google-news
nslayoutconstraint
wikimapia
network-protocols
polymaps
wildfly-9
metabase
okio
ndk-build
fragmentstatepageradapter
bbc-micro
powerpoint-2013
frame-grab
gravatar
certificate-authority
diawi
servicestack-bsd
lowercase
supercomputers
phpredis
abstract-factory
clarion
shoes
rfc5545
juttle
password-recovery
utf8-decode
otl
siena
code-complexity
django-sites
iosched
rautomation
unrealscript
eager-loading
asp.net-mvc-3-areas
simplecov
jquery-dialog
differentiation
will-paginate
data-dump
database-deadlocks
resharper-5.1
rational-unified-process
wmd-editor
data-retrieval
autobench
version-control-migration
code-camp

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