Rust并没有继承的语法,但是你可以定义一个接口作为其他接口的超集。例如:
trait Person {
fn name(&self) -> String;
}
// Person is a supertrait of Student.
// Implementing Student requires you to also impl Person.
trait Student: Person {
fn university(&self) -> String;
}
trait Programmer {
fn fav_language(&self) -> String;
}
// CompSciStudent (computer science student) is a subtrait of both Programmer
// and Student. Implementing CompSciStudent requires you to impl both supertraits.
trait CompSciStudent: Programmer + Student {
fn git_username(&self) -> String;
}
fn comp_sci_student_greeting(student: &dyn CompSciStudent) -> String {
format!(
"My name is {} and I attend {}. My favorite language is {}. My Git username is {}",
student.name(),
student.university(),
student.fav_language(),
student.git_username()
)
}
fn main() {}
代码解析
在Rust中:
- 没有传统面向对象的继承,但是trait有层级关系。
- supertrait(父接口):当一个trait要求实现者必须同时实现另一个trait时。
- subtrait(子接口):依赖于其他的trait。
基础trait定义
trait Person {
fn name(&self) -> String;
}
父接口的关系
// Student 是 Person 的 subtrait
// 实现 Student 必须同时实现 Person
trait Student: Person {
fn university(&self) -> String;
}
trait Programmer {
fn fav_language(&self) -> String;
}
多个父接口
// CompSciStudent 需要同时实现 Programmer 和 Student
// 而 Student 又需要实现 Person,所以实际上需要三个 trait 的实现
trait CompSciStudent: Programmer + Student {
fn git_username(&self) -> String;
}
使用示例
fn comp_sci_student_greeting(student: &dyn CompSciStudent) -> String {
format!(
"My name is {} and I attend {}. My favorite language is {}. My Git username is {}",
student.name(), // 来自 Person
student.university(), // 来自 Student
student.fav_language(), // 来自 Programmer
student.git_username() // 来自 CompSciStudent
)
}
实现要求
如果要实现ComSciStudent,必须:
- 实现Person 接口
- 实现Student接口(包含Person)
- 实现Programmer接口
- 最后实现ComSciStudent接口
与继承的区别
- 组合而非基础:这是接口的组合,而不是类型的继承
- 零成本抽象:没有运行时开销
- 灵活性:可以实现多个不相关的接口
- 显式关系:必须声明trait之间的关系
使用场景
构建有逻辑层次关系的抽象
要求某些能力必须与其他能力一起存在
创建越来越具体的接口,并同时保持灵活性。