Description
Given the following code: (playground)
use std::io::{self, BufRead};
fn main() {
let locked = io::stdin().lock();
for line in locked.lines() {
println!("{}", line.unwrap());
}
}
The current output is:
Compiling playground v0.0.1 (/playground)
error[E0716]: temporary value dropped while borrowed
--> src/main.rs:3:18
|
3 | let locked = io::stdin().lock();
| ^^^^^^^^^^^ - temporary value is freed at the end of this statement
| |
| creates a temporary which is freed while still in use
4 | for line in locked.lines() {
| ------ borrow later used here
|
= note: consider using a `let` binding to create a longer lived value
error: aborting due to previous error
For more information about this error, try `rustc --explain E0716`.
error: could not compile `playground`
To learn more, run the command again with --verbose.
I think it's typical for a newcomer to want to get a Lines
iterator by chaining method calls like io::stdin().lock().lines()
. There's no obvious reason why that shouldn't work. The examples in the std::io
documentation do typically show io::stdin()
being assigned to a variable prior to calling its .lock()
method, but don't explain why that's necessary.
I think the "borrow" terminology is misleading, but there might not be a concise way to describe what's actually going on to the user. The "temporary value is freed at the end of this statement" is probably correct. The "creates a temporary which is freed while still in use" is probably more correctly "creates a temporary that is required to outlive (or live exactly as long as) the result of...", followed by a pointer to the .lock()
method invocation, with text of "...this method call". Maybe it should also point out the '_
lifetime argument in the StdinLock<'_>
return type.
I tried and failed to find a satisfactory explanation of what exactly StdinLock
was borrowing from the temporary Stdin
value produced by io::stdin()
. When I looked through the library source code, the only references in StdinLock
were those created by locking a Mutex
, and the Mutex
in question is static. I'm guessing the existence of a borrow is assumed rather than inferred from analyzing the function body of io::Stdin::lock()
. The assumption might be the result of the anonymous lifetime argument on the output type StdinLock<'_>
from io::Stdin::lock()
, which imposes a requirement that the StdinLock
doesn't outlive (or has the same lifetime as?) the Stdin
value that is the receiver of lock()
.
The correct fix might be to change the locked stdin handles to all use 'static
lifetimes, but I will probably file that as a separate issue.