Using `let` bindings to increase lifetime

I am learning Rust and I wrote the following code to read an array of integers from stdin :

 use std::io; fn main() { for line in io::stdin().lines() { let xs:Vec<int> = line.unwrap().as_slice().trim().split(' ') .map(|s|from_str::<int>(s).unwrap()).collect(); println!("{}", xs); } } 

This worked fine, however, I felt the let xs line was a bit long, so I split it into two parts:

 fn main() { for line in io::stdin().lines() { let ss = line.unwrap().as_slice().trim().split(' '); let xs:Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); println!("{}", xs); } } 

It didn’t work! Rust responded with the following error:

 hello.rs:4:12: 4:25 error: borrowed value does not live long enough hello.rs:4 let ss = line.unwrap().as_slice().trim().split(' '); ^~~~~~~~~~~~~ hello.rs:3:34: 7:3 note: reference must be valid for the block at 3:33... hello.rs:3 for line in io::stdin().lines() { hello.rs:4 let ss = line.unwrap().as_slice().trim().split(' '); hello.rs:5 let xs:Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); hello.rs:6 println!("{}", xs); hello.rs:7 } hello.rs:4:3: 4:54 note: ...but borrowed value is only valid for the statement at 4:2; consider using a `let` binding to increase its lifetime hello.rs:4 let ss = line.unwrap().as_slice().trim().split(' '); ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: aborting due to previous error 

It bothers me. Is it a line or ss that doesn't live long enough? And how can I use let binding to increase their lifespan? I thought I was already using let?

I searched the Internet for solutions and read the Lifetime guide , but I still can't figure it out. Can someone give me a hint?

+7
let rust lifetime
source share
2 answers

In your second version, the type is ss CharSplits<'a, char> . The lifetime parameter in the type tells us that the object contains a link. For an assignment to be valid, the reference must point to an object that exists after this statement. However, unwrap() consumes line ; in other words, it moves Ok data options from the Result object. Therefore, the link does not point inside the original line , but rather a temporary object.

In your first version, you are consuming the temporary end of a long expression, although calling map . To fix your second version, you need to bind the result of unwrap() to keep the value long enough:

 use std::io; fn main() { for line in io::stdin().lines() { let line = line.unwrap(); let ss = line.as_slice().trim().split(' '); let xs: Vec<int> = ss.map(|s|from_str::<int>(s).unwrap()).collect(); println!("{}", xs); } } 
+9
source share

This is about calling unwrap() , which gets the contained object, but this link must survive the container object that goes out of scope in the next line (there is no local binding to it).

If you want cleaner code, a very common way to write it is:

 use std::io; fn main() { for line in io::stdin().lines() { let xs:Vec<int> = line .unwrap() .as_slice() .trim() .split(' ') .map( |s|from_str::<int>(s).unwrap() ) .collect(); println!("{}", xs); } } 

If not, you can create a binding to the "unprepared" result and use it.

Hope this helped.

+3
source share

All Articles