簡體   English   中英

類型與迭代器特征對象的 Peekable 不匹配

[英]type mismatch with Peekable of Iterator trait object

這段代碼編譯得很好:

use std::iter::Peekable;

struct Token {
    length: u32,
}

fn get_tokens() -> Box<dyn Iterator<Item = Token>> {
    todo!()
}

fn do_something_with_boxed_filter(boxed: Box<dyn Iterator<Item = Token>>) {}

fn main() {
    let tokens = get_tokens();
    let long_tokens = tokens.filter(|token| token.length > 32);
    let boxed = Box::new(long_tokens);
    do_something_with_boxed_filter(boxed);
}

但是如果我嘗試制作一個可窺視的版本,如下所示,它無法編譯。

use std::iter::Peekable;

struct Token {
    length: u32,
}

fn get_tokens() -> Box<dyn Iterator<Item = Token>> {
    todo!()
}

fn do_something_with_peekable(peekable: Peekable<Box<dyn Iterator<Item = Token>>>) {}

fn main() {
    let tokens = get_tokens();
    let long_tokens = tokens.filter(|token| token.length > 32);
    let boxed = Box::new(long_tokens);
    let peekable = boxed.peekable();
    do_something_with_peekable(peekable);
}

錯誤信息是:

error[E0308]: mismatched types
  --> src/main.rs:18:32
   |
15 |     let long_tokens = tokens.filter(|token| token.length > 32);
   |                                     ------------------------- the found closure
...
18 |     do_something_with_peekable(peekable);
   |                                ^^^^^^^^ expected trait object `dyn Iterator`, found struct `Filter`
   |
   = note: expected struct `Peekable<Box<(dyn Iterator<Item = Token> + 'static)>>`
              found struct `Peekable<Box<Filter<Box<dyn Iterator<Item = Token>>, [closure@src/main.rs:15:37: 15:62]>>>`

For more information about this error, try `rustc --explain E0308`.

我不明白這一點; Filter結構實現了Iterator所以我不應該使用Filter結構來代替dyn Iterator trait 對象嗎?

是的,你說的都是對的。

問題是您只能將內容輸入可以強制執行的函數中。

如果T: Trait ,則Box<T>可強制轉換為Box<dyn Trait> 但是,在撰寫本文時,這僅深入了一層。 Peekable<Box<T>>不能被強制轉換為Peekable<Box<dyn Trait>> 因此,您需要在創建Peekable之前強制強制執行:

use std::iter::Peekable;

struct Token {
    length: u32,
}

fn get_tokens() -> Box<dyn Iterator<Item = Token>> {
    todo!()
}

fn do_something_with_peekable(peekable: Peekable<Box<dyn Iterator<Item = Token>>>) {}

fn main() {
    let tokens = get_tokens();
    let long_tokens = tokens.filter(|token| token.length > 32);
    let boxed = Box::new(long_tokens) as Box<dyn Iterator<Item = Token>>;
    let peekable = boxed.peekable();
    do_something_with_peekable(peekable);
}

另一種方法是使用impl關鍵字:

use std::iter::Peekable;

struct Token {
    length: u32,
}

fn get_tokens() -> Box<dyn Iterator<Item = Token>> {
    todo!()
}

fn do_something_with_peekable(peekable: Peekable<Box<impl Iterator<Item = Token>>>) {}

fn main() {
    let tokens = get_tokens();
    let long_tokens = tokens.filter(|token| token.length > 32);
    let boxed = Box::new(long_tokens);
    let peekable = boxed.peekable();
    do_something_with_peekable(peekable);
}

使用impl不會發生強制 Box<dyn Trait>是一個 Box 到一個 unsized trait 類型,其中Box<impl Trait>實際上是一個實現Trait的真實類型。 它是什么類型的信息不會丟失給編譯器, impl Trait實際上是用於引入通用Box<T> where T: Trait的語法糖。

impl有優點也有缺點。 最大的缺點是,就像普通的泛型一樣,它為每個使用它的類型編譯一個新版本的函數(我認為)。

優點是根本不再需要Box

use std::iter::Peekable;

struct Token {
    length: u32,
}

fn get_tokens() -> impl Iterator<Item = Token> {
    vec![].into_iter()
}

fn do_something_with_peekable(peekable: Peekable<impl Iterator<Item = Token>>) {}

fn main() {
    let tokens = get_tokens();
    let long_tokens = tokens.filter(|token| token.length > 32);
    let peekable = long_tokens.peekable();
    do_something_with_peekable(peekable);
}

請注意, Peekable<dyn Trait>的兩個對象的類型始終相同,而兩個Peekable<impl Trait>對象的類型可能不同。 Peekable<dyn Trait>一個類型,而Peekable<impl Trait>不是一個類型,它更像是一個類型的占位符。 因此,您不能將Peekable<impl Trait>的不同對象存儲在一個向量中,因為該向量不知道該選擇哪種類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM