trait(特徵)相似於其餘語言中的interface或者protocol,指定一個實際類型必須知足的功能集合git
1、如何理解trait,能夠從咱們所瞭解的接口特性去推斷trait的用法github
1. 那麼做爲一個類接口的關鍵字,意味着被它修飾的類不包含實現的方法fn,只定義函數名稱和參數,由這個類的實現類去完成它的方法。
2. 任何實現接口的類都必須去實現接口的方法,這種特性剛好能夠做爲一種從上到下的約束,應用到Rust語法裏面。
3. 接口也能夠不斷被繼承,最後實現類需要實現全部的接口裏的方法。函數
2、trai的實現方式工具
1. 定義接口開發工具
trait HasArea {
fn area(&self) ->f64;
}spa
2. 實現接口繼承
爲一個結構體圓增長一個計算圓面積的函數:
接口
struct Circle {
x:f64,
y:f64,
radius:f64,
}ci
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
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的實現者並不要求實現它,若是選擇實現它,會覆蓋掉它的默認行爲。
3、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