本文介绍了为什么引用的迭代器项不转换为特征对象引用?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试定义一个函数,该函数应该接收一个迭代器,其中每个项目都是对特征对象的引用。例如:

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));
}

当我尝试在迭代器上调用它时,每个项目都是对实现 Display 的类型:

When I try to call it on an iterator where each item is a reference to a type implementing 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));

对于单个项目也可以使用:

It also works fine for a single item:

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



let item: u32 = 1;
show_item(&item);


推荐答案

类型 T 到 Dyn Trait 来实现 Trait T实现是所谓的,一种特殊的强制手段。尽管Rust不太愿意进行隐式类型转换,但强制确实会在,但不在其他地方。

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. While Rust is somewhat reluctant with implicit type conversions, coercions do happen implicitly at coercion sites, but not in other places.

函数调用参数是强制站点。这就解释了为什么 show_item()函数可以按预期工作。

Function call arguments are coercion sites. This explains why your show_item() function works as desired.

所有强制也可以使用 as 运算符。因此,使用 map()的版本可以正常工作。

All coercions can also be performed explicitly using the as operator. For this reason, the version using map() works fine.

您对的定义show_items()

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

是一个完全不同的故事。此处使用的 impl 语法是

on the other hand is a completely different story. The impl syntax used here is a shorthand for

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

该函数在迭代器类型上是 generic ,并且编译器验证您实际传入的类型是否实现了特征绑定 Iterator< ; Item =&'a dyn Display> 。示例代码中的类型 std :: slice :: Iter<’_,u32> 根本不会,因此会出现错误。没有强制将参数转换为其他类型以使其实现通用函数所需的某些特征绑定的强制转换。还完全不清楚将 std :: slice :: Iter<'_,u32> 转换为&的迭代器的类型; 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>. The type std::slice::Iter<'_, u32> from you example code simply does not, hence the error. 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.

请注意,您的函数定义版本由于需要对特征对象进行迭代而不必要地受到限制。简单地要求迭代器项实现 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:

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

(我还将 Iterator 更改为 IntoIterator ,因为它更通用,更方便。)

(I also changed Iterator to IntoIterator, since this is more general and more convenient.)

这篇关于为什么引用的迭代器项不转换为特征对象引用?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-14 08:44