rust外围三角分离_你如何在Rust中声明一个接口?

I have multiple types with similar methods. I want to abstract over them by writing an interface, like I would in Java:

public interface Shape {

public float area();

}

class Circle implements Shape {

public float area() {

return radius * radius * Math.PI;

}

public float radius;

}

However, there is no interface keyword in Rust. Doesn't Rust offer the possibility to abstract over multiple types?

解决方案

TL;DR: The closest to interface in Rust is a trait. However, do not expect it to be similar in all point to an interface. My answer does not aim to be exhaustive but gives some elements of comparison to those coming from other languages.

If you want an abstraction similar to interface, you need to use Rust's traits:

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())

}

However, it is an error to see a Rust trait as an equivalent of OOP interface. I will enumerate some particularities of Rust's traits.

Dispatch

In Rust, the dispatch (i.e. using the right data and methods when given a trait) can be done in two ways:

Static dispatch

When a trait is statically dispatched, there is no overhead at runtime. This is an equivalent of C++ templates; but where C++ uses SFINAE, the Rust compiler checks the validity using the "hints" we give to him:

fn display_area(shape: &T)

where

T: Shape,

{

println!("area is {}", shape.area())

}

All is explicit: with where T: Shape, we say to the compiler that our generic type T implements Shape, therefore we can use the method Shape::area on our shape.

In this case, like in C++ templates, the compiler will generate a different function for each different type passed in.

Dynamic dispatch

In our first example:

fn display_area(shape: &dyn Shape) {

println!("area is {}", shape.area())

}

the dispatch is dynamic. This is an equivalent to using an interface in C#/Java or an abstract class in C++.

In this case, the compiler does not care about the type of shape. The right thing to do with it will be determined at runtime, at a very slight cost.

Separation between data and implementation

As you see, the data is separated from the implementation; like, for example, C# extension methods. Moreover, one of the utilities of a trait is to extend the available methods on a value:

trait Hello {

fn say_hello(&self);

}

impl Hello for &'static str {

fn say_hello(&self) {

println!("Hello, {}!", *self)

}

}

fn main() {

"world".say_hello();

}

This separation is true also at the lowest level. In case of dynamic dispatch, the method is given two pointers: one for the data, and another for the methods (the vtable).

Default implementation

The trait has one more thing than a classic interface: it can provide a default implementation of a method (just like the "defender" method in Java 8). Example:

trait Hello {

fn say_hello(&self) {

println!("Hello there!")

}

}

impl Hello for i32 {}

fn main() {

123.say_hello(); // call default implementation

}

To use classic OOP words, this is like an abstract class without variable members.

No inheritance

The Rust trait's system is not an inheritance system. You cannot try to downcast, for example, or try to cast a reference on a trait to another trait. To get more information about this, see this question about upcasting.

Moreover, you can use the dynamic type to simulate some behavior you want.

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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值