Newbie lifetime issue (involving Box<Read>, stdin.lock())


I’m writing a parser. My main parse function takes a &mut Box<Read>. I can get this to work with stdin, but can’t get it to work with stdin.lock():

use std::io::{self, Read};

fn main() {
    let stdin = io::stdin();
    let mut handle = stdin.lock();
    let mut read_box: Box<Read> = Box::new(handle);
    read(&mut read_box);

fn parse(source: &mut Box<Read>) {

The error: 5:27 error: `stdin` does not live long enough     let mut handle = stdin.lock();
note: reference must be valid for the static lifetime... 8:2 note: ...but borrowed value is only valid for the block suffix following statement 0 at 4:28

Any idea what I’m doing wrong?

Tangent: I’m using Box<Read> instead of a T:Read type parameter because I don’t want to the parser code to be specialized for each type of input source (stdin, file, etc). Does that make sense or am I misunderstanding things?


The problem is that Box<Trait> is actually Box<Trait + 'static>, meaning that whatever type is hiding behind Trait has to not be bound to any lifetime shorter than 'static.

This is a problem, because .lock() is borrowing stdin, and stdin (by virtue of being a local) is not 'static.

The solution is to be less restrictive:

fn parse<'a>(source: &mut Box<Read + 'a>) {

This allows the type behind Read to be borrowed for just the duration of the call to parse.


Ah, thanks!

It looks like lifetime elision does this automatically for &T (which is what allowed me to be ignorant of this until now) but not for Box<T>. Is that correct?


No; that would imply that &T is bound by the 'static lifetime, which isn’t the case.

In the case of &T, the trait implicitly has the same lifetime as the pointer itself; &Trait is really &'a (Trait + 'a). Boxes don’t have lifetime restrictions, so it makes sense that they get 'static by default.