![](/img/trans.png)
[英]Why are implementations of Iterator<Item = T> and Iterator<Item = &T> conflicting?
[英]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)
}
return
map
和max
Option::unwrap_or
提供默認值。 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.