【问题标题】:What's the idiomatic way to create a iterator that owns some intermediate data and also points to it?创建拥有一些中间数据并指向它的迭代器的惯用方法是什么?
【发布时间】:2020-08-02 02:27:39
【问题描述】:

我正在尝试创建一个环绕 stdin 的结构,以提供类似于 C++ 的 std::cin 的内容。

我想保留一个 String 与当前输入行和一个 SplitAsciiWhitespace 迭代器到它的当前令牌。当我到达迭代器的末尾时,我想换行。

我不担心错误检查,我对任何 crate 都不感兴趣。这不是用于生产代码,仅用于练习。我想避免使用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()
    }
}

This question 解释了为什么它不能以这种方式完成,但没有提供替代解决方案。 “我该如何修复它”部分只是说“不要将这两个东西放在同一个结构中”,但我想不出一种方法来分开做,同时保持与用户相似的界面。

【问题讨论】:

  • 链接问题的主要答案是否有一个“我该如何解决?”部分。这个问题应该解释为什么本节不适用于此处。
  • 你可能会做些什么来解决它的草图:play.rust-lang.org/…
  • 链接的问题在其建议的解决方案中有点过于笼统。我只是在考虑它如何应用于我的案例,或者是否有更好的方法来解决这个问题。
  • @PeterHall,我最终找到了一个类似的解决方案。我只是想知道是否有办法在不使用unsafe 的情况下做到这一点。我将把它添加到问题中。

标签: rust


【解决方案1】:

找到了一个解决方案:使用一个简单的索引来跟踪到目前为止我们已经读取了多少字符串。

它确实需要一些指针运算,但似乎工作得很好。

不确定这是否算作“惯用的”Rust。

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;
        }
    }
}

【讨论】:

    猜你喜欢
    • 2020-12-23
    • 2012-11-14
    • 2016-03-27
    • 2011-06-01
    • 2023-01-08
    • 2019-12-26
    • 2015-09-06
    • 2019-03-17
    • 1970-01-01
    相关资源
    最近更新 更多