Cannot infer an appropriate lifetime

I am trying to write a small utility to be able to load integers from stdin. Intention was to be able to read as many integers as needed by the program.

However, I get below error when trying to compile this.
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements

I understand what the error is saying, but I can't figure out how to resolve it.

I have 2 questions here.

  1. Am I doing something that shouldn't be done? If yes, what is the right way to go about it?
  2. If this is acceptable requirement, what should I do to fix it?

Rust Playground Link:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2015&gist=5b05881daad8aa0ba4c36d8f3aba9258

use std::io;

 mod sca2 {
        use std::str::SplitWhitespace;
        use std::io;
        use std::str;

        pub struct Scanner<'a, R> {
            reader: R,
            buffer: String,
            buf_iter: SplitWhitespace<'a>,
        }

        impl<'a, R: io::BufRead> Scanner<'a, R> {
            pub fn new(reader: R) -> Self {
                Scanner {
                    reader: reader,
                    buffer: String::new(),
                    buf_iter: "".split_whitespace(),
                }
            }

            pub fn token<T: str::FromStr>(&mut self) -> T {
                loop {
                    if let Some(token) = self.buf_iter.next() {
                        return token.parse().ok().expect("Failed parse");
                    }
                    self.buffer.clear();
                    self.reader.read_line(&mut self.buffer).expect("Failed read");
                    // self.buf_iter =  unsafe {
                    //     let slice = str::from_utf8_unchecked(&self.buffer);
                    //     std::mem::transmute(slice.split_whitespace())
                    // };
                    self.buf_iter = self.buffer.split_whitespace();
                }
            }
        }
    }

    fn main() {
        let stdin = io::stdin();
        let mut scan = sca2::Scanner::new(stdin.lock());
        let n: i32 = scan.token();

        println!("{}", n);
    }

self.buffer.split_whitespace() splits a string in different substrings separate by unicode white-spaces, but that substrings is given in the form of &str referencing a slice of the input string(in this case self.buffer), so it does not generate any new string but references slices of the original one, And that is a problem for the lifetime check, Rust have not way of knowing, that you after break the loop will not call self.buffer.clear() or something, if you only want a list of token I recommend to you simply iterate through the result of split_whitespace to build a Vec of owned tokens(Strings)

1 Like

Fix this error by tying the input lifetime to the SplitWhitespace<'a> lifetime.

impl<'a, R: io::BufRead> Scanner<'a, R> {
    pub fn token<T: str::FromStr>(&'a mut self) -> T {
        // ------------------------^^ Add the lifetime annotation here
    }
}

Next, you run into mutable aliasing with the self.buffer.clear() call wanting to mutably borrow the same memory that self.buffer.split_whitespace() is already borrowing. Fix that by reordering the code.

pub fn token<T: str::FromStr>(&'a mut self) -> T {
    if let Some(token) = self.buf_iter.next() {
        return token.parse().ok().expect("Failed parse");
    }

    loop {
        self.buffer.clear();
        self.reader.read_line(&mut self.buffer).expect("Failed read");
        self.buf_iter = self.buffer.split_whitespace();

        loop {
            if let Some(token) = self.buf_iter.next() {
                return token.parse().ok().expect("Failed parse");
            }
        }
    }
}
1 Like

Your recommended changes worked. I was able to read one integer from stdin. However, when I tried to read a second integer, the scan pops the below error.

46 |         let n: i32 = scan.token();
   |                      ---- first mutable borrow occurs here
47 |         let m: i32 = scan.token();
   |                      ^^^^
   |                      |
   |                      second mutable borrow occurs here
   |                      first borrow later used here

As mentioned by sandmor, SplitWhitespace iterator yields references to the original slice self.buffer and you could call self.buffer.clear() between two calls of Scanner::token. The solution proposed by parasyte fixes the issue however it mutably borrows a Scanner for its entire lifetime, only allowing a single method call on a given scanner instance. You should probably get rid of lifetimes here by consuming the SplitWhitespace and storing an iterator of owned Strings. It requires more allocations but it is memory safe.

use std::io;

mod sca2 {
    use std::io;
    use std::str;

    pub struct Scanner<R> {
        reader: R,
        buf_iter: <Vec<String> as IntoIterator>::IntoIter,
    }

    impl<R: io::BufRead> Scanner<R> {
        pub fn new(reader: R) -> Self {
            Scanner {
                reader,
                buf_iter: Vec::new().into_iter(),
            }
        }

        pub fn token<T: str::FromStr>(&mut self) -> T {
            loop {
                if let Some(token) = self.buf_iter.next() {
                    return token.parse().ok().expect("Failed parse");
                }
                let buffer = &mut String::new();
                self.reader.read_line(buffer).expect("Failed read");
                self.buf_iter = buffer
                    .split_whitespace()
                    .map(String::from)
                    .collect::<Vec<_>>()
                    .into_iter();
            }
        }
    }
}

fn main() {
    let stdin = io::stdin();
    let mut scan = sca2::Scanner::new(stdin.lock());

    loop {
        let n: i32 = scan.token();
        println!("{}", n);
    }
}
1 Like