簡體   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