Внедрение признака для нескольких типов одновременно

У меня две структуры и черта:

struct A { x: u32, } struct B { x: u32, } trait T { fn double(&self) -> u32; } 

Я хотел бы реализовать T для обеих структур, используя x .

Есть ли способ написать что-то вроде

 impl T for A, B { fn double(&self) -> u32 { /* ... */ } } 

Я не хотел бы использовать macros, если это возможно.

Единственный способ реализовать черту один раз для многих конкретных типов – реализовать черту для всех типов, уже реализующих другой признак.

Например, вы можете реализовать маркерный признак Xed а затем:

 impl Double for T where T: Xed, { fn double(&self) { /* ... */ } } 

Однако у Rust есть принципиальные дженерики. Единственное, что вы знаете о T в предыдущей реализации, это то, что T реализует trait Xed , и поэтому единственными связанными типами / функциями, которые вы можете использовать, являются те, которые поступают из Xed .

Черта не может выставлять поле / атрибут, только связанные типы, константы и функции, поэтому Xed понадобится getter для x (который не нужно называть x ).

Если вы хотите полагаться на синтаксические (а не семантические ) свойства кода, используйте macros.

Создание макроса также решает вашу проблему:

 struct A { x: u32, } struct B { x: u32, } trait T { fn double(&self) -> u32; } macro_rules! impl_T { (for $($t:ty),+) => { $(impl T for $t { fn double(&self) -> u32 { self.x * 2 } })* } } impl_T!(for A, B); fn main() {} 

Поскольку внутренние структуры ваших структур одинаковы / совместно используют общие компоненты, вы должны извлечь их в общую структуру и вставить общую часть обратно в родительские структуры. Общая структура будет иметь «сложную» реализацию признака, а затем реализация свойств родительской структуры передаст общую реализацию:

 trait T { fn double(&self) -> u32; } struct A { common: Common, } impl T for A { fn double(&self) -> u32 { self.common.double() } } struct B { common: Common, } impl T for B { fn double(&self) -> u32 { self.common.double() } } struct Common { x: u32, } impl T for Common { fn double(&self) -> u32 { self.x * 2 } } 

Любой более удобный код потребует изменений на языке. Два возможных пути:

  • Поля в чертах
  • Делегация
  • Можно ли сделать тип только подвижным и не копируемым?
  • Как инициализировать поля структуры, которые ссылаются друг на друга
  • Что такое monoморфизация с контекстом на C ++?
  • Вектор объектов, принадлежащих признаку
  • Преобразовать строку в int в Rust?
  • Как закончить заимствование в матче или если выражать?
  • Не удается выйти из заемного контента
  • Когда мне следует реализовать std :: convert :: From vs std :: convert :: Into?
  • Есть ли способ объединить несколько признаков, чтобы определить новый признак?
  • Как программа Rust может получать доступ к метаданным из своего пакета Cargo?
  • Как вы используете импорт родительского модуля в Rust?
  • Давайте будем гением компьютера.