Какой идиоматический c способ создать итератор, который владеет некоторыми промежуточными данными и также указывает на них? - PullRequest
2 голосов
/ 19 апреля 2020

Я пытаюсь создать структуру, которая охватывает stdin, чтобы обеспечить что-то вроде std::cin.

в C ++. Я хочу сохранить String с текущей строкой ввода и SplitAsciiWhitespace итератор к своему текущему токену. Когда я достигаю конца итератора, я хочу получить новую строку.

Меня не беспокоит проверка ошибок, и я не заинтересован в каких-либо ящиках. Это не для производственного кода, это просто для практики. Я хочу избегать использования unsafe, чтобы практиковать правильное мышление.

Идея состоит в том, что я могу использовать его следующим образом:

let mut reader = Reader::new();
let x: i32 = reader.read();
let s: f32 = reader.read();

Моя текущая попытка заключается в следующем , но это не компилируется. Может кто-нибудь дать мне указание на правильный способ сделать это?

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()
    }
}

Этот вопрос объясняет , почему это не может быть сделано таким образом, но не предоставить альтернативное решение. В разделе «Как это исправить» просто говорится «не помещайте эти две вещи в одну и ту же структуру», но я не могу придумать, как сделать это отдельно, сохранив интерфейс, подобный пользователю.

1 Ответ

0 голосов
/ 21 апреля 2020

Нашел решение: отследить, сколько строки мы уже прочитали, используя простой индекс.

Требуется некоторая арифметика указателей c, но, похоже, она работает хорошо.

Не уверен, считается ли это "idiomati c" Rust, tho.

struct Reader {
    line: String,
    offset: usize,
}

impl Reader {
    fn new() -> Self {
        Reader { line: String::new(), offset: 0 }
    }
    fn next<T: std::str::FromStr + std::default::Default> (&mut self) -> T {
        loop {
            let rem = &self.line[self.offset..];
            let token = rem.split_whitespace().next();
            if let Some(token) = token {
                self.offset = token.as_ptr() as usize - self.line.as_ptr() as usize + token.len();
                return token.parse::<T>().unwrap_or_default();
            }
            self.line.clear();
            std::io::stdin().read_line(&mut self.line).unwrap();
            self.offset = 0;
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...