【问题标题】:Rust - Multiple Calls to Iterator MethodsRust - 多次调用迭代器方法
【发布时间】:2020-10-26 08:47:10
【问题描述】:

我有以下锈代码:

fn tokenize(line: &str) -> Vec<&str> {
    let mut tokens = Vec::new();
    let mut chars = line.char_indices();
    for (i, c) in chars {
        match c {
            '"' => {
                if let Some(pos) = chars.position(|(_, x)| x == '"') {
                    tokens.push(&line[i..=i+pos]);
                } else {
                    // Not a complete string
                }
            }
            // Other options...
        }
    }
    tokens
}

我试图优雅地从该行中提取一个用双引号括起来的字符串,但是由于 chars.position 采用可变引用并且 chars 被移入 for 循环,我得到一个编译错误 - “移动后借用的值”。编译器建议在 for 循环中借用 chars,但这不起作用,因为不可变引用不是迭代器(可变引用会导致原始问题,我不能再次可变地借用 position)。

我觉得应该有一个简单的解决方案。 有没有一种惯用的方法来做到这一点,还是我需要回归到一个一个地附加字符?

【问题讨论】:

    标签: rust iterator


    【解决方案1】:

    因为for 循环将获得chars 的所有权(因为它调用.into_iter()),您可以改为使用while 循环手动迭代chars

    fn tokenize(line: &str) -> Vec<&str> {
        let mut tokens = Vec::new();
        let mut chars = line.char_indices();
        while let Some((i, c)) = chars.next() {
            match c {
                '"' => {
                    if let Some(pos) = chars.position(|(_, x)| x == '"') {
                        tokens.push(&line[i..=i+pos]);
                    } else {
                        // Not a complete string
                    }
                }
                // Other options...
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      如果你只是对 for 循环脱糖,它就可以工作:

      fn tokenize(line: &str) -> Vec<&str> {
          let mut tokens = Vec::new();
          let mut chars = line.char_indices();
          while let Some((i, c)) = chars.next() {
              match c {
                  '"' => {
                      if let Some(pos) = chars.position(|(_, x)| x == '"') {
                          tokens.push(&line[i..=i+pos]);
                      } else {
                          // Not a complete string
                      }
                  },
                  _ => {},
              }
          }
          tokens
      }
      

      正常的 for 循环防止对迭代器进行额外修改,因为这通常会导致令人惊讶且难以阅读的代码。将其作为 while 循环执行没有这样的保护。

      如果您只想找到带引号的字符串,那么我根本不会在这里使用迭代器。

      fn tokenize(line: &str) -> Vec<&str> {
          let mut tokens = Vec::new();
          let mut line = line;
          while let Some(pos) = line.find('"') {
              line = &line[(pos+1)..];
              if let Some(end) = line.find('"') {
                  tokens.push(&line[..end]);
                  line = &line[(end+1)..];
              } else {
                  // Not a complete string
              }
          }
          tokens
      }
      

      【讨论】:

      • 谢谢!我也做其他事情,而不仅仅是查找带引号的字符串 - 这正是导致问题的原因。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-06-30
      • 1970-01-01
      • 2020-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多