简体   繁体   English

为什么引用的迭代器项不转换为特征对象引用?

[英]Why are iterator items which are references not cast to a trait object reference?

I'm trying to define a function that should receive an iterator where each item is a reference to a trait object. 我试图定义一个应该接收迭代器的函数,其中每个项目都是对特征对象的引用。 For example: 例如:

use std::fmt::Display;

fn show_items<'a>(items: impl Iterator<Item = &'a Display>) {
    items.for_each(|item| println!("{}", item));
}

When I try to call it on an iterator where each item is a reference to a type implementing Display : 当我尝试在迭代器上调用它时,其中每个项目都是对实现Display的类型的引用:

let items: Vec<u32> = (1..10).into_iter().collect();
show_items(items.iter());

I get an error: 我收到一个错误:

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>) {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Why is &u32 not considered as &dyn std::fmt::Display ? 为什么&u32不被视为&dyn std::fmt::Display

An explicit cast works fine: 显式强制转换可以正常工作:

show_items(items.iter().map(|item| item as &Display));

It also works fine for a single item: 它也可以用于单个项目:

fn show_item(item: &Display) {
    println!("{:?}", item);
}
let item: u32 = 1;
show_item(&item);

The implicit conversion from a type T to dyn Trait for a Trait implemented by T is a so-called unsized coercion , a special kind of coercion. 从类型的隐式转换Tdyn TraitTrait通过实施T是所谓的未分级的强制 ,一种特殊形式的胁迫。 While Rust is somewhat reluctant with implicit type conversions, coercions do happen implicitly at coercion sites , but not in other places. 尽管Rust不太愿意使用隐式类型转换,但强制确实会在强制站点上隐式发生,而在其他地方却不会。

Function call arguments are coercion sites. 函数调用参数是强制站点。 This explains why your show_item() function works as desired. 这解释了为什么show_item()函数可以show_item()工作。

All coercions can also be performed explicitly using the as operator. 还可以使用as运算符显式执行所有强制。 For this reason, the version using map() works fine. 因此,使用map()的版本可以正常工作。

Your definition of show_items() , 您对show_items()定义,

fn show_items<'a>(items: impl Iterator<Item = &'a Display>)

on the other hand is a completely different story. 另一方面是完全不同的故事。 The impl syntax used here is a shorthand for 这里使用的impl语法是的简写

fn show_items<'a, I>(items: I)
where
    I: Iterator<Item = &'a dyn Display>,

The function is generic over the iterator type, and the compiler verifies that the type that you actually pass in implements the trait bound Iterator<Item = &'a dyn Display> . 该函数在迭代器类型上是通用的,并且编译器验证您实际传入的类型是否实现了特征绑定Iterator<Item = &'a dyn Display> The type std::slice::Iter<'_, u32> from you example code simply does not, hence the error. 示例代码中的类型std::slice::Iter<'_, u32>根本没有,因此出现错误。 There is no coercion that converts an argument to a different type to make it implement some trait bound required by a generic function. 没有强制将参数转换为其他类型以使其实现通用函数所需的某些特征绑定的强制转换。 It is also entirely unclear what type to convert std::slice::Iter<'_, u32> to to turn it into an iterator over &dyn Display . 还完全不清楚将std::slice::Iter<'_, u32>转换为通过&dyn Display进行迭代的类型。

Note that your version of the function definition is unnecessarily restrictive by requiring an iterator over trait objects. 请注意,您的函数定义版本由于需要对特征对象进行迭代而不必要地受到限制。 It would be far more natural and more performant to simply require that the iterator items implement Display instead: 仅要求迭代器项改为实现Display会更自然,更高效:

fn show_items<I>(items: I)
where
    I: IntoIterator,
    I::Item: Display,

(I also changed Iterator to IntoIterator , since this is more general and more convenient.) (我也将Iterator更改为IntoIterator ,因为这更通用,更方便。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM