Если для Strategy
характерна следующая impl
, то она может быть параметризована не на том месте.(Я собираюсь игнорировать связанный тип для этого ответа, потому что пример не использует его.)
impl<E: HasData<Data = ExampleData>> Strategy<E> for ExampleStrat {
fn run(&self, e: &E) {
let _ = e.data();
// uses ExampleData here
}
}
Вместо этого вы можете параметризовать Strategy
сверх D
- ломая impl
цикл зависимости - и параметризация только метода run
над E
.
pub trait Strategy<D> {
fn run(&self, &impl HasData<Data = D>);
}
impl Strategy<ExampleData> for ExampleStrat {
fn run(&self, e: &impl HasData<Data = ExampleData>) {
let _ = e.data();
// uses ExampleData here
}
}
fn run<E: HasData<Data = ExampleData>>(&self, e: &E)
- это еще один способ определить run
, который является одинаковым для этой цели. Вот полный пример .
Потенциальным недостатком этого подхода является то, что run
нельзя вызывать через объект признака Strategy
, поскольку он должен быть мономорфизирован для любоготип, который реализует HasData
.Но черта HasData
, похоже, мало что делает в этом impl
: единственное, что она может сделать, это вернуть внутреннюю ссылку, и как только она у вас есть, нет смысла использовать ее снова.Может быть, run
может просто взять ссылку &D
?
pub trait Strategy<D> {
fn run(&self, &D);
}
impl Strategy<ExampleData> for ExampleStrat {
fn run(&self, _: &ExampleData) {
// uses ExampleData here
}
}
Конечно, теперь вам нужно позвонить self.s.run(self.data())
в do_it
, но это не будет стоить вам гибкости по сравнению соригинальная версия, в которой, если бы она работала…, вы могли бы вызывать Strategy<E>::run
только с аргументом типа &E
.
На самом деле, вся черта HasData
кажется мне ненужной: она всегда реализуетсятот же тип, реализация которого вызывает его, поэтому, за исключением незначительного удобства передачи self
вместо self.data
, он не повышает уровень абстракции внутри метода do_it
.Таким образом, мне кажется, что одно и то же удалить HasData
полностью и дать Example
знать, как вызвать Strategy::run
с правильной ссылкой;в любом случае(Однако, возможно, мне просто не хватает воображения.)
Любое из этих решений должно обрабатывать добавление связанного типа к Strategy
, но, не зная, как он будет использоваться, трудно сказать наверняка.
tIt можно заставить работать в какой-то будущей версии компилятора с достаточно умной проверкой типов.