Rust语言开发基础(八)Rust的接口及其实现

原创
2016/04/09 21:14
阅读数 6.7K

trait(特征)类似于其他语言中的interface或者protocol,指定一个实际类型必须满足的功能集合

一、如何理解trait,可以从我们所了解的接口特性去推断trait的用法

1. 那么作为一个类接口的关键字,意味着被它修饰的类不包含实现的方法fn,只定义函数名称和参数,由这个类的实现类去完成它的方法。
2. 任何实现接口的类都必须去实现接口的方法,这种特性恰好可以作为一种从上到下的约束,应用到Rust语法里面。
3. 接口也可以不断被继承,最后实现类须要实现所有的接口里的方法。

 

二、trai的实现方式

1. 定义接口

trait HasArea {
    fn area(&self) ->f64;
}

 

2. 实现接口

为一个结构体圆增加一个计算圆面积的函数:

struct Circle {
    x:f64,
    y:f64,
    radius:f64,
}

impl HasAreaforCircle {
    fn area(&self) ->f64 {
        std::f64::consts::PI* (self.radius *self.radius)
    }
}

----------------------------------------------------------

fn main() {
    let c =Circle {
        x:0.0f64,
        y:0.0f64,
        radius:1.0f64,
    };
    println!("circle c has an area of {}", c.area());
}


最终输出:
circle c has an area of 1


3. 继承接口
trait Foo {
    fn foo(&self);
}

trait FooBar:Foo {
    fn foobar(&self);
}
实现:
struct Baz;

impl FooforBaz {
    fnfoo(&self) { println!("foo"); }
}

impl FooBarforBaz {
    fn foobar(&self) { println!("foobar"); }
}

 

4.自动化实现接口
Rust会自动帮你实现接口,当然必须是某些特定的接口方法,就好像利用开发工具帮你实现一些接口方法一样。
能帮你实现的方法仅限于:Clone,Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd
这些方法一般是常见的方法,要自动实现上述方法,前提是使用derive属性。

#[derive(Debug)]structFoo;

fn main() {
    println!("{:?}",Foo);
}

5.自带默认方法
tait修饰的类都自动被系统加上一个默认方法,这个默认方法不要求被实现类实现,当然实现类可以去实现它并覆盖原有方法。

trait Foo {
    fn is_valid(&self) ->bool;

    fn is_invalid(&self) ->bool { !self.is_valid() }
}
is_invalid是默认方法,Foo的实现者并不要求实现它,如果选择实现它,会覆盖掉它的默认行为。

 

三、Rust里面的应用场景

1.给泛型增加约束,或者说给泛型增加实现要求。
例如:Debug是Rust内置的一个trait,为"{:?}"实现打印内容,函数foo接受一个泛型作为参数,并且约定其需要实现Debug
use std::fmt::Debug;

fn foo<T:Debug>(s:T) {
    println!("{:?}", s);
}


2.给泛型增加多个trait,也即所谓的多重约束。

use std::fmt::Debug;

fn foo<T:Debug+Clone>(s:T) {
    s.clone();
    println!("{:?}", s);
}
<T: Debug + Clone>中Debug和Clone使用+连接,表示泛型T需要同时实现这两个trait。

 

3. where关键字其实只是为多重约束增加一些写法。

标准写法:
use std::fmt::Debug;

fn foo<T:Clone,K:Clone+Debug>(x:T, y:K) {
    x.clone();
    y.clone();
    println!("{:?}", y);
}
where从句写法一:
fn foo<T,K>(x:T, y:K) whereT:Clone,K:Clone+Debug {
    x.clone();
    y.clone();
    println!("{:?}", y);
}
where从句写法二:
fn foo<T,K>(x:T, y:K)
    whereT:Clone,K:Clone+Debug {
    x.clone();
    y.clone();
    println!("{:?}", y);
}
语法糖,这只是语法糖!

 

4.孤僻的应用场景,给内置类型增加trait

trait HasArea {
    fn area(&self) ->f64;
}

impl HasAreafori32 {
    fn area(&self) ->f64 {
        *selfasf64
    }
}

area();


最后的输出接口f64类型的数值,这个方法相当有用

注意:
1. 当你为某类型实现某 trait 的时候,必须要求类型或者 trait 至少有一个是在当前 crate 类库中定义的。你不能为第三方的类型实现第三方的 trait 。
2. 在调用 trait 中定义的方法的时候,一定要记得让这个 trait 可被访问。

 

参考:https://github.com/rustcc/RustPrimer/blob/master/10-trait/10-00-overview.md

 

 

 

 


 

展开阅读全文
加载中

作者的其它热门文章

打赏
1
6 收藏
分享
打赏
0 评论
6 收藏
1
分享
返回顶部
顶部