我有以下函数,该函数应该查找并返回给定String
的{{1}}的最长长度:
Iterator
但是,编译器给我以下错误:
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;
}
我是Rust的新手,对此感到非常困惑,因为我认为我明确地传递了一个迭代器。调用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`
告诉我它没有实现,而调用strings.iter()
则使我陷入了一个易变性的陷阱,而且我当然不想突变传递的参数。
如何遍历我的琴弦?
答案 0 :(得分:8)
您的代码失败,因为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)
}
答案 1 :(得分:3)
其他答案向您展示如何接受迭代器,但掩盖了回答您实际问题的可能性:
为什么不能使用
&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)
}
return
map
和max
之类的迭代器组合器Option::unwrap_or
提供默认值。IntoIterator
接受可以构成迭代器的所有内容。答案 2 :(得分:0)
如果您不特别需要在任何给定的迭代器上进行迭代的通用性,则编写函数的更简单方法是让您的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