我试图定义应该接受一个迭代器,其中每个产品的特性对象的引用的功能。例如:
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
的隐式转换dyn Trait
由Trait
实施T
是所谓unsized coercion,一种特殊形式的胁迫。虽然锈病是隐式类型转换有些勉强,做的强制在coercion sites隐含发生,而不是在其他地方。
函数调用的参数是强制的网站。这就解释了为什么你show_item()
功能工作如期望的那样。
所有的强制也可以使用as
运营商明确地执行。出于这个原因,使用map()
版本工作正常。
你show_items()
的定义,
fn show_items<'a>(items: impl Iterator<Item = &'a Display>)
而另一方面是一个完全不同的故事。这里使用的impl
语法是一个速记
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
,因为这是更通用,更方便。)