Search code examples
rustrust-tokioownership

How to hold borrowed value to struct's filed in Rust


I just want to use tokio::net::TcpStream.split method in a struct and keep it as its field variable, but I got the error error[E0597]: 'stream' does not live long enough. I face this kind of problems many times when I am trying to hold a borrowed value to struct's field like Struct std::path::Path. I know Path problem will be solved with using PathBuf, but I'm not sure this time. Could you give me an advise to make it work?

use tokio::net::TcpStream;
use tokio::net::tcp::{ReadHalf, WriteHalf};

struct TT<'a>{
    pub reader: Option<ReadHalf<'a>>,
    pub writer: Option<WriteHalf<'a>>,
}

impl<'a> TT<'a> {
    fn set_reader_and_writer(&mut self, mut stream: TcpStream) {
        let (reader, writer) = stream.split();
        self.reader = Some(reader);
        self.writer = Some(writer);
    }
}
$ cargo build                                                                                                                                                                    [master|…4]
    Blocking waiting for file lock on build directory
   Compiling tcpst v0.1.0 (/tmp/tcpst)
error[E0597]: `stream` does not live long enough
  --> src/main.rs:11:32
   |
9  | impl<'a> TT<'a> {
   |      -- lifetime `'a` defined here
10 |     fn set_reader_and_writer(&mut self, mut stream: TcpStream) {
11 |         let (reader, writer) = stream.split();
   |                                ^^^^^^ borrowed value does not live long enough
12 |         self.reader = Some(reader);
   |         -------------------------- assignment requires that `stream` is borrowed for `'a`
13 |         self.writer = Some(writer);
14 |     }
   |     - `stream` dropped here while still borrowed

error: aborting due to previous error

For more information about this error, try `rustc --explain E0597`.
error: could not compile `tcpst`.

Solution

  • The problem is that the read and write halves of the stream both borrow references to the stream they were created from. In your code, the original stream is dropped at the end of the function, which would invalidate those references. The easiest solution is to change the signature of set_reader_and_writer to take a &mut stream instead of taking ownership.

    This is a very understandable mistake to make, as the signature for split does not make its lifetimes explicit (that stream must live at least as long as the return values). If you check the source, though, it shows the ReadHalf and WriteHalf lifetimes (and why they were permitted to be elided from the function signature).