Почему элементы итератора, являющиеся ссылками, не приводятся к ссылке на объект черты? - PullRequest
0 голосов
/ 04 февраля 2019

Я пытаюсь определить функцию, которая должна получать итератор, где каждый элемент является ссылкой на объект признака.Например:

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

1 Ответ

0 голосов
/ 04 февраля 2019

Неявное преобразование из типа T в dyn Trait для Trait, реализованное T, представляет собой так называемое нестандартное принуждение , особый вид принуждения.Хотя Rust несколько неохотно работает с неявными преобразованиями типов, приведения действительно происходят неявно в узлах приведения , но не в других местах.

Аргументы вызова функций являются узлами приведения.Это объясняет, почему ваша функция 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, поскольку это более общее и болееудобный.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...