#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 .