编者按:这个代码示例来自Rust 1.0之前的一个版本,当时许多迭代器实现了Copy.此代码的更新版本会产生不同的错误,但答案仍然包含有价值的信息.

我正在try 编写一个函数,将字符串拆分为字母和数字;例如,"test123test"会变成[ "test", "123", "test" ].以下是我迄今为止的try :

pub fn split(input: &str) -> Vec<String> {
    let mut bits: Vec<String> = vec![];
    let mut iter = input.chars().peekable();
    loop {
        match iter.peek() {
            None => return bits,
            Some(c) => if c.is_digit() {
                bits.push(iter.take_while(|c| c.is_digit()).collect());
            } else {
                bits.push(iter.take_while(|c| !c.is_digit()).collect());
            }
        }
    }
    return bits;
}

然而,这不起作用,永远循环.每次我打take_while,它似乎都在使用iter的克隆,从同一个位置一次又一次地开始.我希望它每次使用相同的iter,在所有each_time上推进相同的迭代器.这可能吗?

推荐答案

正如您所指出的,每个take_while调用都重复了iter,因为take_whileselfPeekable个字符的迭代器是Copy.(Only true before Rust 1.0 — editor)

您希望每次都修改迭代器,也就是说,take_while对迭代器的&mut进行操作.这正是.by_ref适配器的用途:

pub fn split(input: &str) -> Vec<String> {
    let mut bits: Vec<String> = vec![];
    let mut iter = input.chars().peekable();
    loop {
        match iter.peek().map(|c| *c) {
            None => return bits,
            Some(c) => if c.is_digit(10) {
                bits.push(iter.by_ref().take_while(|c| c.is_digit(10)).collect());
            } else {
                bits.push(iter.by_ref().take_while(|c| !c.is_digit(10)).collect());
            },
        }
    }
}

fn main() {
    println!("{:?}", split("123abc456def"))
}

输出

["123", "bc", "56", "ef"]

然而,我认为这是不对的.

实际上,我建议使用char_indices迭代器将其作为普通的for循环编写:

pub fn split(input: &str) -> Vec<String> {
    let mut bits: Vec<String> = vec![];
    if input.is_empty() {
        return bits;
    }

    let mut is_digit = input.chars().next().unwrap().is_digit(10);
    let mut start = 0;

    for (i, c) in input.char_indices() {
        let this_is_digit = c.is_digit(10);
        if is_digit != this_is_digit {
            bits.push(input[start..i].to_string());
            is_digit = this_is_digit;
            start = i;
        }
    }

    bits.push(input[start..].to_string());
    bits
}

这种形式还允许用更少的分配来实现这一点(也就是说,不需要String),因 for each 返回值只是input的一部分,我们可以使用生命周期来说明:

pub fn split<'a>(input: &'a str) -> Vec<&'a str> {
    let mut bits = vec![];
    if input.is_empty() {
        return bits;
    }

    let mut is_digit = input.chars().next().unwrap().is_digit(10);
    let mut start = 0;

    for (i, c) in input.char_indices() {
        let this_is_digit = c.is_digit(10);
        if is_digit != this_is_digit {
            bits.push(&input[start..i]);
            is_digit = this_is_digit;
            start = i;
        }
    }

    bits.push(&input[start..]);
    bits
}

改变的只是类型签名,删除了Vec<String>类型提示和.to_string个调用.

人们甚至可以编写这样的迭代器,以避免分配Vec.比如fn split<'a>(input: &'a str) -> Splits<'a> { /* construct a Splits */ },其中Splits是一个实现Iterator<&'a str>的 struct .

Rust相关问答推荐

如何容器化Linux上基于Rust的Windows应用程序的编译过程?

在没有引用计数或互斥锁的情况下,可以从Rust回调函数内的封闭作用域访问变量吗?

下载压缩文件

如何指定不同的类型来常量Rust中的泛型参数?

无法定义名为&new&的关联函数,该函数的第一个参数不是self

如何高效地将 struct 向量中的字段收集到单独的数组中

获取与父字符串相关的&;str的原始片段

为什么Deref类特征不构成?

在 Rust 中,为什么 10 个字符的字符串的 size_of_val() 返回 24 个字节?

如何在 Rust 中打印 let-else 语句中的错误?

将引用移动到线程中

如何获取模块树?

Rust中的位移操作对范围有什么影响?

枚举的利基优化如何在 Rust 中工作?

Rust 中的生命周期:borrow 的 mut 数据

为什么可以在迭代器引用上调用 into_iter?

为什么 Rust 编译器在移动不可变值时执行复制?

为什么可以从闭包中返回私有 struct

当用作函数参数时,不强制执行与绑定的关联类型

为什么 std::iter::Peekable::peek 可变地borrow self 参数?