I'm trying to create a struct that wraps around stdin
to provide something like C++'s std::cin
.
I want to keep a String
with the current line of the input and a SplitAsciiWhitespace
iterator to its current token. When I reach the end of the iterator, I want to get a new line.
I'm not worried about error checking and I'm not interested in any crates. This is not for production code, it's just for practicing. I want to avoid using unsafe
, as a way to practice the correct mindset.
The idea is that I can use it as follows:
let mut reader = Reader::new();
let x: i32 = reader.read();
let s: f32 = reader.read();
My current attempt is the following, but it doesn't compile. Can somebody give me a pointer on the proper way to do this?
struct Reader<'a> {
line: String,
token: std::str::SplitAsciiWhitespace<'a>,
}
impl<'a> Reader<'a> {
fn new() -> Self {
let line = String::new();
let token = line.split_ascii_whitespace();
Reader { line, token }
}
fn read<T: std::str::FromStr + std::default::Default>(&'a mut self) -> T {
let token = loop {
if let Some(token) = self.token.next() {
break token;
}
let stdin = io::stdin();
stdin.read_line(&mut self.line).unwrap();
self.token = self.line.split_ascii_whitespace();
};
token.parse().unwrap_or_default()
}
}
This question explains why it can't be done this way but does not provide an alternative solution. The "How do I fix it" section simply says "don't put these two things in the same struct", but I can't think of a way to do it separately while keeping a similar interface to the user.