TL;DR: rust 迹中最接近界面是一种特征.然而,not希望它在所有方面都与接口类似.我的回答并非详尽无遗,而是提供了一些与其他语言进行比较的元素.
如果你想要一个类似于界面的抽象,你需要使用Rust的trait
:
trait Shape {
fn area(&self) -> f32;
}
struct Circle {
radius: f32,
}
impl Shape for Circle {
fn area(&self) -> f32 {
self.radius.powi(2) * std::f32::consts::PI
}
}
struct Square {
side: f32,
}
impl Shape for Square {
fn area(&self) -> f32 {
self.side.powi(2)
}
}
fn main() {
display_area(&Circle { radius: 1. });
display_area(&Square { side: 1. });
}
fn display_area(shape: &dyn Shape) {
println!("area is {}", shape.area())
}
然而,it is an error to see a Rust trait as an equivalent of OOP interface.我将列举Rust's trait
的一些特殊性.
Dispatch
在Rust中,调度(i.e.在给定特征时使用正确的数据和方法)可以完成in two ways:
静态调度
当一个trait被静态调度时,运行时没有开销.这是一个等价的C++模板;但是,C++使用SFIEAE时,RIST编译器使用我们给他的"提示"来判断有效性:
fn display_area(shape: &impl Shape) {
println!("area is {}", shape.area())
}
对于impl Shape
,我们告诉编译器我们的函数有一个实现Shape
的泛型类型参数,因此我们可以在shape
上使用方法Shape::area
.
在这种情况下,像C++模板一样,编译器将为传入的每个不同类型生成不同的函数.
动态调度
在我们的第一个例子中:
fn display_area(shape: &dyn Shape) {
println!("area is {}", shape.area())
}
调度是动态的.这相当于在C++ java中使用接口或者C++中的抽象类.
在本例中,编译器不关心shape
的类型.使用它的正确方法将在运行时确定,通常成本很低.
Separation between data and implementation
如您所见,数据与实现是分离的;比如,C#扩展方法.此外,trait的一个实用功能是在一个值上扩展可用的方法:
trait Hello {
fn say_hello(&self);
}
impl Hello for &'static str {
fn say_hello(&self) {
println!("Hello, {}!", *self)
}
}
fn main() {
"world".say_hello();
}
这样做的一大优点是,您可以在不修改数据的情况下实现数据的特征.相比之下,在classic 的面向对象语言中,必须修改类以实现另一个接口.换言之,您可以为外部数据实现自己的特性.
This separation is true also at the lowest level.在动态分派的情况下,方法有两个指针:一个用于数据,另一个用于方法(vtable).
Default implementation
与classic 接口相比,trait还有一个优点:它可以提供方法的默认实现(就像Java8中的"defender"方法).例子:
trait Hello {
fn say_hello(&self) {
println!("Hello there!")
}
}
impl Hello for i32 {}
fn main() {
123.say_hello(); // call default implementation
}
用classic 的OOP语言来说,这就像一个没有变量成员的抽象类.
No inheritance
Rust 特性的系统不是遗传系统.例如,你不能试图贬低,或者试图把一个特征的参照物与另一个特征联系起来.欲了解更多信息,请参阅this question about upcasting.
此外,您可以使用dynamic type来模拟所需的某些行为.
While you can simulate the inheritance mechanism in Rust with various tricks, this is a better idea to use idiomatic designs instead of twist the language to a foreign way of thinking that will uselessly make grow the complexity of code.
你应该阅读铁 rust 书中的the chapter about traits来了解更多关于这个话题的内容.