[英]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.