rust - 如何在 Rust 中正确使用 `peek()`?

标签 rust iterator regex-lookarounds peek

我正在尝试做一些简单的事情。在 u8 的切片中, 我想找到两个字符的出现 "\r\n" .但是,我无法将该切片转换为 String使用 from_utf8因为 "\r\n" 之后的切片部分可能不是 utf-8 并且尽可能我不想使用 from_utf8_unchecked .所以我尝试了类似以下的方法。

fn find_crlf(text: &[u8]) -> Option<usize> {
    let mut textiter = text.iter().peekable();

    for (idx, &elem) in textiter.enumerate() {
        if Some(&elem) == Some(&b'\r') {
            if textiter.peek() == Some(&&b'\n') {
                return Some(idx);
            }
        }
    }
    None
}

我得到以下编译错误,这是可以理解的。但是,我不太确定如何执行此操作。如果是 str ,它只是.find("\r\n") .

编译错误->

error[E0382]: borrow of moved value: `textiter`
 --> src/lib.rs:6:16
  |
2 |     let mut textiter = text.iter().peekable();
  |         ------------ move occurs because `textiter` has type `std::iter::Peekable<std::slice::Iter<'_, u8>>`, which does not implement the `Copy` trait
3 | 
4 |     for (idx, &elem) in textiter.enumerate() {
  |                         -------- value moved here
5 |         if Some(&elem) == Some(&b'\r') {
6 |             if textiter.peek() == Some(&&b'\n') {
  |                ^^^^^^^^ value borrowed here after move

可能是我错过了一些非常简单的东西,但现在已经坚持了很长一段时间。

最佳答案

通常,编写此类代码的最佳方法是不使用 Peekable根本。这是一个使用起来很棘手的 API,因为您经常想调用 peek当您处于迭代过程中时,这通常意味着您已经可变地借用了迭代器,因此您不能再次借用它。
但是,既然你问了 Peekable具体来说,您可以重写代码以显式调用 next在循环中,这通常是使用 peek 的唯一方法:

fn find_crlf(text: &[u8]) -> Option<usize> {
    let mut textiter = text.iter().enumerate().peekable();
    while let Some((idx, &elem)) = textiter.next() {
        if Some(&elem) == Some(&b'\r') {
            if let Some((_, &b'\n')) = textiter.peek() {
                return Some(idx);
            }
        }
    }
    None
}
通常,更好的前瞻方法是使用 slice::windowstuple_windows来自 itertools .
鉴于您的输入是一个切片,您可以使用 slice::windows :
fn find_crlf(text: &[u8]) -> Option<usize> {
    for (idx, window) in text.windows(2).enumerate() {
        if window[0] == b'\r' && window[1] == b'\n' {
            return Some(idx);
        }
    }
    None
}
不过总的来说,我更喜欢 itertools 的语法。方法,因为您可以在元组上进行模式匹配,这感觉比索引切片更干净:
use itertools::Itertools; // 0.9.0

fn find_crlf(text: &[u8]) -> Option<usize> {
    for (idx, (&elem, &next)) in text.iter().tuple_windows().enumerate() {
        if elem == b'\r' && next == b'\n' {
            return Some(idx);
        }
    }
    None
}
或者,甚至更好:
use itertools::Itertools; // 0.9.0

fn find_crlf(text: &[u8]) -> Option<usize> {
    text.iter()
        .tuple_windows()
        .position(|(elem, next)| elem == &b'\r' && next == &b'\n')
}

关于rust - 如何在 Rust 中正确使用 `peek()`?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62186871/

相关文章:

rust - 如何为用属性本身注释的结构提供字段属性?

rust - 怎么写慌张!像 Rust 中的宏?

C++ STL vector iterator insert segmentation fault 收藏

xsd - 不允许特定字符串的 XML 架构限制模式

regex - 何时在正则表达式中使用正向查找?

rust - 列出范围内由类型实现的所有特征

rust - 线程局部 RefCell 作为 Rust 中局部变量的替换

python - 取消注释 `if False: yield` 更改 `__iter__` 行为

c++ - c++ 按降序对 vector 进行排序

javascript - 正则表达式匹配帮助: won't match on each appearence