Как вы расширяете признак, как это делает itertools с помощью collect_vec()?

#generics #rust #iterator #traits #scoping

#дженерики #Ржавчина #итератор #Трейты #определение области

Вопрос:

Я хотел бы создать метод, аналогичный collect_vec() функции в itertools .

Создание небольшого примера путем копирования itertools кода:

 pub trait MyItertools: Iterator {
    fn collect_vec(self) -> Vec<Self::Item>
        where Self: Sized
    {
        self.collect()
    }
}

fn main() {
    let v = (0..5).collect_vec();
    println!("{:?}", v);
}
 

Я довольно наивно ожидаю, что компилятор будет использовать мой collect_vec as
MyItertools находится в пределах досягаемости.

Должно быть какое-то другое волшебство, которое itertools заставляет это компилироваться.

Мы получаем ошибку:

 error[E0599]: no method named `collect_vec` found for struct `std::ops::Range<{integer}>` in the current scope
  --> src/main.rs:14:20
   |
14 |     let v = (0..5).collect_vec();
   |                    ^^^^^^^^^^^ method not found in `std::ops::Range<{integer}>`
   |
   = help: items from traits can only be used if the trait is implemented and in scope
note: `MyItertools` defines an item `collect_vec`, perhaps you need to implement it
  --> src/main.rs:5:1
   |
5  | pub trait MyItertools: Iterator {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

error: aborting due to previous error
 

Что вводит в заблуждение, поскольку мы действительно реализовали collect_vec MyItertools .

Одним из возможных решений является impl MyItertools для всех вариантов Iterator , но, похоже, нет способа сделать это для всех Iterator реализующих признаков и типов.

Комментарии:

1. Нет, это не так, поскольку вы на самом деле не реализовали MyItertools признак для std::ops::Range (что (0..5) и есть). Вы объявили признак, но на самом деле не реализовали его ни для одного типа (по крайней мере, в вашем MCVE). Чтобы реализовать признак SomeType , вам нужно будет добавить impl MyItertools for SomeType блок (и убедиться, что SomeType Iterator он также реализуется).

2. Спасибо, EvilTalk. Как я предполагаю в своей правке, это можно было бы сделать для всех типов, которые я использую, но Itertools, похоже, этого не делает, отсюда и волшебство.

Ответ №1:

Недостающая волшебная часть головоломки — это общая общая реализация, которая реализует MyItertools признак для всех типов, которые реализуют Iterator признак. Обновленный исправленный пример:

 pub trait MyItertools: Iterator {
    fn collect_vec(self) -> Vec<Self::Item>
        where Self: Sized
    {
        self.collect()
    }
}

impl<T> MyItertools for T where T: Iterator {}

fn main() {
    let v = (0..5).collect_vec();
    println!("{:?}", v);
}
 

игровая площадка

Комментарии:

1. Ага! Отличный ответ, @pretzelhammer .