Как реализовать признак для итераций по двойным ссылкам на один и тот же признак

#rust #traits

#Ржавчина #Трейты

Вопрос:

Предположим, у меня есть признак Tr , определенный как таковой:

 trait Tr {
    fn tr(amp;self);
}
  

У меня есть признак, реализованный для некоторого типа, скажем X :

 struct X;

impl Tr for X {
    fn tr(self) {}
}
  

Теперь я хотел бы impl Tr для любого типа, который можно превратить в итератор по ссылкам на реализацию значений Tr .

Я пробовал это: (игровая площадка)

 impl<T: IntoIterator<Item = impl Tr>> Tr for T {
    fn tr(amp;self) { self.into_iter().for_each(|value| value.tr()) }
}
  

Но он не компилируется, потому IntoIterator::into_iter что принимает self по ходу, а мой признак получает только ссылку.

При этом я попытался также использовать признак self по ходу движения и реализовать его для ссылок: (игровая площадка)

 struct X;
trait Tr {
    fn tr(self);
}

impl Tr for amp;X {
    fn tr(self) {}
}

impl<T: IntoIterator<Item = impl Tr>> Tr for T {
    fn tr(self) { self.into_iter().for_each(|value| value.tr()) }
}
  

Это отлично компилируется, но работает только для коллекций, содержащих значения X . Моя цель состоит в том, чтобы он работал с коллекциями, содержащими ссылки на X , например: [amp;X] .

Чтобы решить эту проблему, я реализовал Tr для двойных ссылок на X , что работает, но выглядит странно: (игровая площадка)

 impl Tr for amp;amp;X {
    fn tr(self) {}
}
  

Это также не позволяет мне напрямую вызывать tr экземпляры X , как это было возможно при использовании impl для одной ссылки: X.tr() и вместо этого я должен поместить X хотя бы одну ссылку, чтобы вызвать tr ее : (amp;X).tr() . Это, конечно, можно решить, добавив еще impl один для одной ссылки, но это значительно увеличивает сложность, когда у меня много типов, которые реализуют Tr .

Вопрос в том, правильно ли это сделать в Rust? Могу ли я каким-либо образом упростить код или вообще избавиться от «взятия self по ходу»?

Редактировать: в идеале результат должен допускать все следующее:

 X.tr();
[amp;X].tr();
vec![amp;X].tr();
(amp;[amp;X]).tr();
(amp;vec![amp;X]).tr();
  

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

1. Это отлично компилируется, но работает только для коллекций, содержащих значения X. Моя цель состоит в том, чтобы он работал с итерациями по ссылкам на X. Хм … это так .

2. @trentcl Возможно, я не слишком четко выразился там. Моя цель — заставить его работать не с итераторами, которые дают ссылки X , а с коллекциями, содержащими ссылки, такие как vec![amp;X] . (что приводит к тому, что итераторы выдают двойные ссылки)