I wrote the following code to read an array of integers from stdin
:
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
let xs: Vec<i32> = line.unwrap()
.trim()
.split(' ')
.map(|s| s.parse().unwrap())
.collect();
println!("{:?}", xs);
}
}
This worked fine, however, I felt the let xs
line was a bit long, so I split it into two:
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
let ss = line.unwrap().trim().split(' ');
let xs: Vec<i32> = ss.map(|s| s.parse().unwrap()).collect();
println!("{:?}", xs);
}
}
This didn't work! Rust replied with the following error:
error[E0597]: borrowed value does not live long enough
--> src/main.rs:6:18
|
6 | let ss = line.unwrap().trim().split(' ');
| ^^^^^^^^^^^^^ - temporary value dropped here while still borrowed
| |
| temporary value does not live long enough
...
10 | }
| - temporary value needs to live until here
|
= note: consider using a `let` binding to increase its lifetime
This confuses me. Is it line
or ss
that doesn't live long enough? And how can I use a let
binding to increase their lifetime? I thought I was already using a let
?
I've read through the lifetime guide, but I still can't quite figure it out. Can anyone give me a hint?
In your second version, the type of ss
is Split<'a, char>
. The lifetime parameter in the type tells us that the object contains a reference. In order for the assignment to be valid, the reference must point to an object that exists after that statement. However, unwrap()
consumes line
; in other words, it moves Ok
variant's data out of the Result
object. Therefore, the reference doesn't point inside the original line
, but rather on a temporary object.
In your first version, you consume the temporary by the end of the long expression, though the call to map
. To fix your second version, you need to bind the result of unwrap()
to keep the value living long enough:
use std::io::{self, BufRead};
fn main() {
let stdin = io::stdin();
for line in stdin.lock().lines() {
let line = line.unwrap();
let ss = line.trim().split(' ');
let xs: Vec<i32> = ss.map(|s| s.parse().unwrap()).collect();
println!("{:?}", xs);
}
}