特点对比
- Trait默认实现:
- Trait定义一组方法签名,可提供部分或全部方法的默认实现。不同结构体可通过
impl Trait for Struct
来实现Trait,实现方式灵活,不局限于类型层次结构。例如:
trait Animal {
fn speak(&self) {
println!("I'm an animal");
}
}
struct Dog;
impl Animal for Dog {}
- 一个结构体可以实现多个Trait,类似于多继承的功能。
- 传统继承机制:
- 子类继承父类,获得父类的属性和方法。子类与父类形成严格的层次结构,例如在Java中:
class Animal {
void speak() {
System.out.println("I'm an animal");
}
}
class Dog extends Animal {}
- 一般情况下,大多数语言只支持单继承,以避免菱形继承问题。
优势对比
- Trait默认实现:
- 灵活性高:不依赖类型层次结构,任何结构体都能实现Trait,不同结构体间只要符合Trait定义就可复用代码。如
Vec
和String
都可实现Iterator
Trait来复用迭代相关代码。
- 支持类似多继承:一个结构体可实现多个Trait,从多个来源复用代码,而传统继承多为单继承。
- 传统继承机制:
- 层次结构清晰:通过继承构建清晰的类型层次,便于理解和维护,如在图形绘制系统中,
Shape
类作为父类,Circle
、Rectangle
等子类继承自它,层次关系一目了然。
- 天然的数据共享:子类可直接访问父类非私有成员,代码复用同时便于数据共享。
劣势对比
- Trait默认实现:
- 缺乏统一层次结构:没有像继承那样清晰的类型层次,对于大型复杂系统设计,可能难以整体把握类型关系。
- 访问控制有限:Trait默认实现中难以像继承那样对子结构体数据进行访问控制,因为Trait不知道实现它的结构体内部具体数据。
- 传统继承机制:
- 单继承局限:多数语言只支持单继承,限制了代码复用来源,不能同时从多个父类复用代码。
- 紧密耦合:子类与父类紧密耦合,父类修改可能影响子类,不利于独立维护和扩展。
合适场景
- Trait默认实现合适场景:
- 通用功能复用:当有一些通用功能,如日志记录、序列化等,不同类型都可能需要时,使用Trait默认实现。例如不同业务逻辑的结构体都需要记录日志,可定义
Logging
Trait并提供默认日志记录方法,各结构体实现该Trait即可复用。
- 行为混入:当想为结构体混入一些行为,且这些行为不适合用继承关系表示时,用Trait默认实现。比如为一个游戏角色结构体混入“可跳跃”行为,定义
Jumpable
Trait并提供默认跳跃逻辑。