为什么作为引用的迭代器项不转换为特征对象引用?
Why are iterator items which are references not cast to a trait object reference?
我正在尝试定义一个应该接收迭代器的函数,其中每个项目都是对特征对象的引用。例如:
use std::fmt::Display;
fn show_items<'a>(items: impl Iterator<Item = &'a Display>) {
items.for_each(|item| println!("{}", item));
}
当我尝试在迭代器上调用它时,其中每个项目都是对实现 Display
:
的类型的引用
let items: Vec<u32> = (1..10).into_iter().collect();
show_items(items.iter());
我收到一个错误:
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, u32> as std::iter::Iterator>::Item == &dyn std::fmt::Display`
--> src/lib.rs:9:5
|
9 | show_items(items.iter());
| ^^^^^^^^^^ expected u32, found trait std::fmt::Display
|
= note: expected type `&u32`
found type `&dyn std::fmt::Display`
note: required by `show_items`
--> src/lib.rs:3:1
|
3 | fn show_items<'a>(items: impl Iterator<Item = &'a Display>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
为什么 &u32
不被视为 &dyn std::fmt::Display
?
显式转换工作正常:
show_items(items.iter().map(|item| item as &Display));
它也适用于单个项目:
fn show_item(item: &Display) {
println!("{:?}", item);
}
let item: u32 = 1;
show_item(&item);
由 T
实现的 Trait
从类型 T
到 dyn Trait
的隐式转换是所谓的 unsized coercion, a special kind of coercion. While Rust is somewhat reluctant with implicit type conversions, coercions do happen implicitly at coercion sites,但不是其他地方。
函数调用参数是强制转换点。这解释了为什么您的 show_item()
功能会按预期工作。
所有强制转换也可以使用 as
运算符显式执行。因此,使用 map()
的版本可以正常工作。
你对show_items()
、
的定义
fn show_items<'a>(items: impl Iterator<Item = &'a Display>)
另一方面是完全不同的故事。这里使用的 impl
语法是 shorthand for
fn show_items<'a, I>(items: I)
where
I: Iterator<Item = &'a dyn Display>,
该函数在迭代器类型上是泛型,编译器会验证您实际传入的类型是否实现了特征绑定Iterator<Item = &'a dyn Display>
。您的示例代码中的类型 std::slice::Iter<'_, u32>
根本没有,因此出现错误。没有将参数转换为不同类型以使其实现泛型函数所需的某些特征绑定的强制转换。也完全不清楚将 std::slice::Iter<'_, u32>
转换为什么类型以将其转换为 &dyn Display
.
上的迭代器
请注意,您的函数定义版本不必要地限制了特征对象的迭代器。简单地要求迭代器项实现 Display
会更自然、更高效:
fn show_items<I>(items: I)
where
I: IntoIterator,
I::Item: Display,
(我也把Iterator
改成了IntoIterator
,因为这样更通用也更方便。)
我正在尝试定义一个应该接收迭代器的函数,其中每个项目都是对特征对象的引用。例如:
use std::fmt::Display;
fn show_items<'a>(items: impl Iterator<Item = &'a Display>) {
items.for_each(|item| println!("{}", item));
}
当我尝试在迭代器上调用它时,其中每个项目都是对实现 Display
:
let items: Vec<u32> = (1..10).into_iter().collect();
show_items(items.iter());
我收到一个错误:
error[E0271]: type mismatch resolving `<std::slice::Iter<'_, u32> as std::iter::Iterator>::Item == &dyn std::fmt::Display`
--> src/lib.rs:9:5
|
9 | show_items(items.iter());
| ^^^^^^^^^^ expected u32, found trait std::fmt::Display
|
= note: expected type `&u32`
found type `&dyn std::fmt::Display`
note: required by `show_items`
--> src/lib.rs:3:1
|
3 | fn show_items<'a>(items: impl Iterator<Item = &'a Display>) {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
为什么 &u32
不被视为 &dyn std::fmt::Display
?
显式转换工作正常:
show_items(items.iter().map(|item| item as &Display));
它也适用于单个项目:
fn show_item(item: &Display) {
println!("{:?}", item);
}
let item: u32 = 1;
show_item(&item);
由 T
实现的 Trait
从类型 T
到 dyn Trait
的隐式转换是所谓的 unsized coercion, a special kind of coercion. While Rust is somewhat reluctant with implicit type conversions, coercions do happen implicitly at coercion sites,但不是其他地方。
函数调用参数是强制转换点。这解释了为什么您的 show_item()
功能会按预期工作。
所有强制转换也可以使用 as
运算符显式执行。因此,使用 map()
的版本可以正常工作。
你对show_items()
、
fn show_items<'a>(items: impl Iterator<Item = &'a Display>)
另一方面是完全不同的故事。这里使用的 impl
语法是 shorthand for
fn show_items<'a, I>(items: I)
where
I: Iterator<Item = &'a dyn Display>,
该函数在迭代器类型上是泛型,编译器会验证您实际传入的类型是否实现了特征绑定Iterator<Item = &'a dyn Display>
。您的示例代码中的类型 std::slice::Iter<'_, u32>
根本没有,因此出现错误。没有将参数转换为不同类型以使其实现泛型函数所需的某些特征绑定的强制转换。也完全不清楚将 std::slice::Iter<'_, u32>
转换为什么类型以将其转换为 &dyn Display
.
请注意,您的函数定义版本不必要地限制了特征对象的迭代器。简单地要求迭代器项实现 Display
会更自然、更高效:
fn show_items<I>(items: I)
where
I: IntoIterator,
I::Item: Display,
(我也把Iterator
改成了IntoIterator
,因为这样更通用也更方便。)