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

Use different impl when type parameters are the same
Weird characters when using cursive SelectView
How to return a instance of a struct that uses a locally declared variable [duplicate]
Cannot infer an appropriate lifetime when calling a mutable method with references passed as closure arguments
How to access the element at variable index of a tuple?
Iron::new()::http() intercepts stdin
Join futures with limited concurrency
How to get Racer working with Atom?
How do I compile the raw-cpuid crate in rust?
Anonymous enum in Rust
Lifetime of references in closures
Why can't the Option.expect() message be downcast as a &'static str when a panic is handled with catch_unwind?
Why does the Rust documentation say that sharing a reference to a vector would create an invalid vector even though the vector is on the heap?
Polymorphism in Rust and trait references (trait objects?)
Setting the include path with bindgen
In Rust, how can a reference be a pointer to a pointer-to-a-pointer?

Categories

HOME
hpoo
rust
matrix
xcode
functional-programming
yaml
couchdb
operating-system
informatica
consul
turbojpeg
share
responsive-design
lda
lc3
twitter-oauth
fireloop
phpstorm-2017.1
smooks
freertos
fresco
bnf
temperature
gravity
maven-plugin
unity-container
kamailio
liferay-6.2
candlestick-chart
backendless
android-service
annotation-processing
d3.js-v4
matlab-app-designer
autodesk-model-derivative
vcenter
series
overwrite
mongoengine
directfb
netstat
testlink
xvfb
jade4j
ms-solver-foundation
django-crispy-forms
microsoft-ui-automation
selenide
google-now
imgur
right-click
swfupload
system-on-chip
robust
linq-to-excel
section508
webalizer
nusoap
sharpdx
android-mediarecorder
glimpse
business-rules
perl-data-structures
oid
streamwriter
libharu
logical
gcloud-node
mathml
node.js-connect
univocity
msgpack
juniper-network-connect
arbre
espresso
postal-code
modern.ie
angular-amd
actionpack
physicsjs
juttle
rubber
xcode6.3.1
thruway
cpu-time
cloo
saga
colon
san
reentrancy
struts2-s2hibernate
mvcrecaptcha
groovy-console
kohana-auth
fragment-identifier
jquery-1.4
multiple-users
3-tier
urchin
iphone-sdk-4.3
resharper-5.0
mysqli-multi-query
source-code-protection
data-retrieval
ntruencrypt
isapi-redirect
account-management

Resources

Database Users
RDBMS discuss
Database Dev&Adm
javascript
java
csharp
php
android
javascript
java
csharp
php
python
android
jquery
ruby
ios
html
Mobile App
Mobile App
Mobile App