繁体   English   中英

为什么我不能使用`&Iterator <Item = &String> `作为迭代器?

[英]Why can't I use `&Iterator<Item = &String>` as an iterator?

我有以下函数,它应该在给定Iterator找到并返回String的最长长度:

fn max_width(strings: &Iterator<Item = &String>) -> usize {
    let mut max_width = 0;
    for string in strings {
        if string.len() > max_width {
            max_width = string.len();
        }
    }
    return max_width;
}

但是,编译器给出了以下错误:

error[E0277]: the trait bound `&std::iter::Iterator<Item=&std::string::String>: std::iter::Iterator` is not satisfied
 --> src/main.rs:3:19
  |
3 |     for string in strings {
  |                   ^^^^^^^ `&std::iter::Iterator<Item=&std::string::String>` is not an iterator; maybe try calling `.iter()` or a similar method
  |
  = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Iterator<Item=&std::string::String>`
  = note: required by `std::iter::IntoIterator::into_iter`

我是Rust的新手,对此非常困惑,因为我以为我是在显式传递一个迭代器。 调用strings.iter()告诉我它没有实现,并调用strings.into_iter()向我发送一个可变性的兔子洞,我当然不想改变传递的参数。

如何迭代我的字符串?

您的代码失败,因为Iterator&Iterator 如果你将Iterator传递给你的函数,你可以解决这个问题,但由于Iterator是一个特征,因此无法确定大小(你无法知道,你传递的是什么Iterator )。 解决方案是传递任何实现Iterator东西:

fn max_width<'a>(strings: impl Iterator<Item = &'a String>) -> usize

操场


对于更有经验的Rust用户:

最通用的方式可能是:

fn max_width<T: AsRef<str>>(strings: impl IntoIterator<Item = T>) -> usize {
    let mut max_width = 0;
    for string in strings {
        let string = string.as_ref();
        if string.len() > max_width {
            max_width = string.len();
        }
    }
    max_width
}

操场

但是,您也可以使用

fn max_width<T: AsRef<str>>(strings: impl IntoIterator<Item = T>) -> usize {
    strings
        .into_iter()
        .map(|s| s.as_ref().len())
        .max()
        .unwrap_or(0)
}

操场

其他答案向您展示如何接受迭代器,但是在回答您的实际问题时会有光泽:

为什么我不能使用&Iterator<Item = &String>作为迭代器?

有趣的是,你自己阻止了它:

我当然不想改变传递的论点

迭代器通过改变目标来工作 - 这就是迭代器如何改变以为每个调用返回一个新值!

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
    //       ^^^
}

通过接受一个不可变的trait对象 ,你的迭代器不可能自我更新,因此实际迭代是不可能的。

你可以做的绝对最小的事情就是接受一个可变的引用:

fn max_width(strings: &mut dyn Iterator<Item = &String>) -> usize

但是,我可能会将函数编写为:

fn max_width<I>(strings: I) -> usize
where
    I: IntoIterator,
    I::Item: AsRef<str>,
{
    strings
        .into_iter()
        .map(|s| s.as_ref().len())
        .max()
        .unwrap_or(0)
}
  1. 不要使用显式return
  2. 使用迭代器组合器,如mapmax
  3. 使用Option::unwrap_or提供默认值。
  4. 使用IntoIterator接受任何可以作为迭代器的东西。

如果你没有特别需要迭代任何给定迭代器的一般性,那么编写函数的一种更简单的方法是让你的max_width函数取一个&[&str] (一片字符串切片)。 您可以在for循环中使用切片,因为Rust知道如何将其转换为迭代器(它实现了IntoIterator特征):

fn max_width(strings: &[&str]) -> usize {
    let mut max_width = 0;
    for string in strings {
        if string.len() > max_width {
            max_width = string.len();
        }
    }
    return max_width;
}

fn main() {
    let strings = vec![
        "following",
        "function",
        "supposed",
        "return",
        "longest",
        "string",
        "length"
    ];

    let max_width = max_width(&strings);

    println!("Longest string had size {}", max_width);
}

// OUTPUT: Longest string had size 9

这里的游乐场

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM