Я иногда осознавал, что все вхождения определенной черты связаны с другими чертами. В вашем случае, если AppState
всегда происходит с Clone
и Serialize
, вам может потребоваться это в верхней части состояния:
trait AppState : Clone + Serialize {/*...*/}
Если нет, вы все равно можете определить вспомогательную черту
trait AuxAppState: AppState + Clone + Serialize {/*...*/}
и потребовать State : AuxAppState
.
Затем, чтобы автоматически получить AuxAppState
, вам потребуется impl
для каждого типа, который также impl
элементы State
, Clone
и Serialize
:
impl<T> AuxAppState for T where T: AppState + Clone + Serialize {}
Наконец, определение и impl
добавление AuxAppState
может быть выполнено макросом для сохранения некоторых нажатий клавиш :
macro_rules! auxiliary_trait{
($traitname: ident, $($t:tt)*) => {
trait $traitname : $($t)* {}
impl<T> $traitname for T where T: $($t)* {}
}
}
Все это возможно сделать за один день с псевдонимами признаков .
Более того, я начал требовать границы признаков только там, где они действительно необходимы , Например, во многих случаях само определение struct
не полагается на границы признаков, только impl
, поэтому я начал опускать их на struct
, оставляя их только в impl
.