Вот решение, основанное на ночной функции специализация :
#![feature(specialization)]
use std::fmt::Debug;
struct A(i32);
#[derive(Debug)]
struct B(i32);
struct Foo<T> {
data: T,
/* more fields */
}
trait Do {
fn do_something(&self);
}
impl<T> Do for Foo<T> {
default fn do_something(&self) {
/* ... */
println!("Success!");
}
}
impl<T> Do for Foo<T>
where
T: Debug,
{
fn do_something(&self) {
/* ... */
println!("Success on {:?}", self.data);
}
}
fn main() {
let foo = Foo {
data: A(3), /* ... */
};
foo.do_something(); // should call first implementation, because A
// doesn't implement Debug
let foo = Foo {
data: B(2), /* ... */
};
foo.do_something(); // should call second implementation, because B
// does implement Debug
}
Первый шаг - создать черту, которая определяет do_something(&self)
. Теперь мы определим два impl
этой черты для Foo<T>
: общий «родитель» impl
, который реализован для всех T
, и специализированный «потомок» impl
, который реализован только для подмножества, где T
реализует Debug
. Дочерний impl
может специализировать предметы от родителя impl
. Эти элементы, которые мы хотим специализировать, должны быть помечены ключевым словом default
в родительском элементе impl
. В вашем примере мы хотим специализироваться do_something
.