Rust的trait特征

·1081·3 分钟·
AI摘要: 本文详细介绍了Rust语言中的trait特性,包括其基本用法、继承与多继承操作、静态分发和动态分发机制。通过示例代码展示了如何定义和实现trait,以及使用Send和Sync约束实现者的能力。文章还对比了trait与接口的不同之处,解释了静态分发(编译时确定类型并生成高效代码)和动态分发(运行时查找具体实现)的原理及性能差异。

Rust中也有类似其他语言中的接口之类的特性,即trait,不过rust对其进行了增强,能实现许多功能

基本使用

pub trait Parser{
	fn parse(&self, input: &str) -> String;
}

那么实现这个trait

struct CommonVideoParser;

impl Parser for CommonVideoParser{
    fn parse(&self, input: &str) -> String {
        fomat!("Parsed: {}", input)
    }
}

除此之外,也能进行类似继承和多继承的操作

pub trait Parser: Send {
    fn parse(&self, input: &str) -> String;
}

pub trait Parser: Send + Sync {
    fn parse(&self, input : & str) -> String;
}
  • Send是Rust提供的一种trait bound,用来约束实现者,主要是可以把这个类型的转移到另外一个线程里
  • Sync 可以把这个类型的引用&T安全地在线程之间共享

不同与接口的地方

trait约等于接口,但是比接口更强。

静态分发

编译器在编译的时候就知道了类型,直接生成高效代码, 这种泛型+trait的写法,类似于C++的模板:

fn run<T: Parser>(p: T) {
    println!("{}", p.parse("hi"));
}

当我们传入CommonVideoParser的时候,编译器就知道了T的类型为CommonVideoParser(之前只知道p是一个实现了Parser trait的东西,但是具体是哪个东西不清楚),然后直接生成一份专门为CommonVideoParser写的run代码。

动态分发

类似java的多态,用虚表实现

fn run(p: &dyn Parser) {
    println!("{}", p.parse("hi"));
}

在这个run中,当传入p为CommonVideoParser的时候,但是p是一个&dyn Parser,所以编译器只知道p是一个实现了Parser trait的某个东西,但是具体的不清楚,需要再运行时候,根据需要去找具体的实现。类似于java的多态,性能低一点