为什么这是不投的特质对象引用引用迭代器的项目?

问题描述 投票:0回答:1

我试图定义应该接受一个迭代器,其中每个产品的特性对象的引用的功能。例如:

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);
casting reference rust traits
1个回答
3
投票

从类型T的隐式转换dyn TraitTrait实施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,

(我也改变IteratorIntoIterator,因为这是更通用,更方便。)

© www.soinside.com 2019 - 2024. All rights reserved.