2020 Rust 特征 (Trait)

rust.jpeg

選擇 rust 的理由

  • Rust 有助于您提供代碼質量
    • 讓我們更加明確地了解性能成本
    • 便于開發(fā)人員權衡代碼性能利弊
  • Rust 更加關注代碼的質量和正確性
    • 強調(diào)內(nèi)存安全,除非指定了"unsafe"
    • 強大的類型系統(tǒng)咬扇、匹配系統(tǒng)
  • 寫 Rust 有一種寫 kotlin 或者 go 這些高級語言的感覺

特征

組成我們應用通常是兩個部分數(shù)據(jù)行為鹃共,我們編程多半工作就是用行為操作數(shù)據(jù)。

fn make_true(input:&str) -> String{
    format!("{}!!",input)
}

定義函數(shù) make_true 對字符串進行操作松靡,然后返回字符串滞详,這是對數(shù)據(jù)的操作。

#[derive(Debug)]
struct Fact {
    text: String
}

fn make_true(input:&Fact) -> Fact{
    Fact{text:format!("{}!!",input.text)}
}

?往往將字符串定義在范圍箩言,我們將字符串作為對象 Fact 的屬性,然后 make_true 接收 Fact 對象然后對其 text 屬性進行操作焕襟。

我們希望方法與數(shù)據(jù)有一定關系陨收,也就是方法屬于數(shù)據(jù),或者說想要將方法添加到數(shù)據(jù)上鸵赖,在其他語言是 method务漩。在 rust 為結構體添加行為很簡單,

  • 通過關鍵字 impl 其后添加要添加方法到結構體名稱
  • 然后寫實現(xiàn)
impl Fact {
    fn make_true(&self) -> Fact{
        Fact{text:format!("{}!!",self.text)}
    }
}


fn main(){
   
    let fact = Fact{text:String::from("hello")};
    println!("{:#?}",fact.make_true());
}

上面代碼大家疑問最多可能就是 self它褪,為什么我們需要 self

  • 通過 self 方法可以訪問到數(shù)據(jù)
  • 所以結構體內(nèi)實現(xiàn)方法饵骨,都會得到數(shù)據(jù)引用作為方法第一個參數(shù),然后來通過 self 引用來訪問數(shù)據(jù)茫打,類似 javascript 和 java 中的 this居触。
    根據(jù)需要可以指定不同 self
  • &self 借用滨砍、只讀版本
  • &mut self 可變借用版本
  • [mut] self: 所有版本方妖,可以操作修改 self
impl Fact {
    fn make_true(&mut self){
        self.text.push_str("!!");
    }
}
impl Fact {
    fn make_true(mut self) -> Fact{
        self.text.push_str("!!");
        self
    }
}

let fact = Fact{text:String::from("hello")};
let fact_1 = fact.make_true();
println!("{:#?}",fact_1.text);

特征定義

trait 用于定義與其他類型共享功能旺韭,這是一種抽象钙态,類似于其他語言(例如 go 語言)中的接口些膨。今天將介紹如何創(chuàng)建 trait 以及其實現(xiàn)和使用渗磅,最后會給出基于 trait 實現(xiàn)日志系統(tǒng)翼岁。

定義 trait

抽象方式定義共享的行為


pub trait GetInformation {
    fn get_title(&self)-> &String;
    fn get_course(&self)-> u32;
}

使用 trait 關鍵字來定義特征楼肪,然后在其中定義一系列行為开财,也就是空方法汉柒,需要結構體去實現(xiàn)。

pub struct Tut {
    pub title: String,
    pub course: u32,
}

impl GetInformation for Tut {
    fn get_title(&self) -> &String{
        &self.title
    }
    // u32 天然具有 copy 特征
    fn get_course(&self) -> u32{
        self.course
    }
}

定義結構體實現(xiàn)特征 GetInformation 的 get_title 這個結構體就具有 GetInfomation 特征责鳍。

fn main() {

    let js_tut = Tut{title:"vue".to_string(),course:10};
    println!("js_tut title = {} course = {}",js_tut.get_title(),js_tut.get_course())
}

在 go 語言我們可以根據(jù)行為進行劃分類別竭翠,只要具有行為結構體就屬于某一個按類別進行劃分的類別。有時候我們傳入結構體薇搁,需要具有一定能力斋扰。

實現(xiàn) trait

作為參數(shù)輸入結構體需要具有一定行為,也就是結構體實現(xiàn)某種特征

fn print_information(tut:impl GetInformation){
    println!("title = {}",tut.get_title());
    println!("age = {}",tut.get_course())
}


fn main() {

    let js_tut = Tut{title:"vue".to_string(),course:10};
    // println!("js_tut title = {} course = {}",js_tut.get_title(),js_tut.get_course())
    print_information(js_tut);

}

默認 Trait 實現(xiàn)

有些時候我們可以通過給出默認方法的實現(xiàn)啃洋,也就是給方法提供默認行為传货。

trait TutInfo {
    fn get_tut_info(&self) -> String{
        String::from("supplied by zidea zone")
    }
}

定義 TutInfo 特征,然后給行為定義默認行為宏娄,如果實現(xiàn)特征 TutInfo 沒有復寫 get_tut_info 方法時就會默認執(zhí)行 TutInfo 特征默認提供的行為问裕。

impl TutInfo for Tut {

    // add code here
}
let js_tut_info = js_tut.get_tut_info();
println!("tut info = {}",js_tut_info);

Trait 邊界

trait 邊界指定泛型是任何擁有特定行為的類型。

fn print_information_two<T:GetInformation>(tut:T){
    println!("title = {}",tut.get_title());
    println!("age = {}",tut.get_course());
}

這里就是使用特征邊界(trait bound)來定義函數(shù)接受參數(shù)需要具有一定約束(要求結構體必須實現(xiàn)某種方法)孵坚,所以約束就是要求結構體需要具有一定能力粮宛。

也可以指定多個特征邊界(train_bound), 來約束對象具有多個行為窥淆。其實語法還是比較好理解,一門新語言帶來很多新的特性巍杈,但是并不能改變你編程和設計程序能力忧饭。只是便于你對程序設計的實現(xiàn)。

trait GetTitle {
    fn get_title(&self) -> &String;
}

trait GetCourse {
    fn get_course(&self) -> u32;
}

impl GetTitle for Tut {
    fn get_title(&self)->&String{
        &self.title
    }
}

impl GetCourse for Tut {
    fn get_course(&self) -> u32{
        self.course
    }
}

fn print_information_three<T:GetTitle+GetCourse>(tut:T){
    println!("title = {}",tut.get_title());
    println!("age = {}",tut.get_course());
}

還有一種特征邊界的寫法筷畦,通過 where 對泛型進行限制词裤,

fn print_information_five<T>(tut:T) where T:GetCourse + GetTitle{

    println!("title = {}",tut.get_title());
    println!("age = {}",tut.get_course());
}

接下來,也可以特征邊界( trait bound) 來約束函數(shù)的返回值類型鳖宾。

fn get_tut() -> impl GetTitle {
    Tut{
        title:String::from("react"),
        course:20
    }
}

這里需要補充一下這里 get_tut 返回值是 trait 類型吼砂,我們不能通過條件來返回不同都實現(xiàn) GetTitle 的不同結構體,這樣會報錯

let reactTut = get_tut();
println!("title of react tut = {}",reactTut.get_title());

Trait 對象

在我們所熟悉的面向對象編程語言中鼎文,對象包含數(shù)據(jù)和行為渔肩。創(chuàng)建對象便可調(diào)用其方法(行為)進行操作。在 rust 我們將數(shù)據(jù)保存在 enums 或是 structs ,而行為寫作 trait 里拇惋,也就是將數(shù)據(jù)和行為分開赖瞒。Trait 對象行為更像傳統(tǒng)的對象。Trait 對象可以包含數(shù)據(jù)和行為蚤假,但是又不同于傳統(tǒng)對象栏饮。

  • 系統(tǒng)日志信息
  • 日志需要可配置
  • 在開發(fā)版提供詳細信息,而在發(fā)布版提供簡要的信息
    定義 Logger 結構體磷仰,添加輸出不同級別日志信息
#[derive(Debug)]
struct Loggger {
}

impl Logger{
    fn error(&self, message:&str){}
    fn warn(&self, message:&str){}
    fn info(&self, message:&str){}
    fn debug(&self, message:&str){}
}

上面定義了不同級別的日志輸出 error, warn, info 和 debug 級別日志輸出

根據(jù)日志輸出形式又定義不同類型日志輸出

  • FilerLogger
  • PrintLogger
  • NullLogger
  • ExternalServiceLoagger
trait Loggger {
    fn error(&self, message:&str);
    fn warn(&self, message:&str);
    fn info(&self, message:&str);
    fn debug(&self, message:&str);
}

#[derive(Debug)]
struct PrintLogger {
}

impl Loggger for PrintLogger {

    fn error(&self, message:&str){
        println!("ERROR:{} ",message)
    }
    fn warn(&self, message:&str){
        println!("ERROR:{} ",message)
    }
    fn info(&self, message:&str){
        println!("ERROR:{} ",message)
    }
    fn debug(&self, message:&str){
        println!("ERROR:{} ",message)
    }
}

?這里我們定義特征 Logger袍嬉,讓不同日志輸出類型都去實現(xiàn) Logger 特征,這樣他們就是不同類型卻具有相同行為的類別

pub fn log_example(logger:&Logger){
    logger.info("runing example code ..");
    logger.info("done example code");
}

這里 &Logger 也稱為Trait 對象灶平,在 Trait 對象中包含

  • 一個指向一個基本類型(可能是 PrintLogger 也可能是 FileLogger)
  • 指針指向虛擬方法表(vtable)
    這些都是由編譯器實現(xiàn)的


    Trait 對象

在 Trait 對象是包含一個指向堆上數(shù)據(jù)指針伺通,以這種形式來保存數(shù)據(jù),當堆上值大小變化不會影響到 Trait 對象逢享,這樣更利于分配內(nèi)存給對象罐监。

 logger.info("runing example code ..");

在上面語句編譯器會先從 vtable 中加載 info 函數(shù)地址,然調(diào)用到 info 函數(shù)的地址瞒爬」看整個過程,可能會擔心效率侧但,這樣做會不會影響程序的性能矢空。

vtable
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市禀横,隨后出現(xiàn)的幾起案子屁药,更是在濱河造成了極大的恐慌,老刑警劉巖柏锄,帶你破解...
    沈念sama閱讀 221,331評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件酿箭,死亡現(xiàn)場離奇詭異复亏,居然都是意外死亡,警方通過查閱死者的電腦和手機缭嫡,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,372評論 3 398
  • 文/潘曉璐 我一進店門缔御,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人械巡,你說我怎么就攤上這事∪氖希” “怎么了讥耗?”我有些...
    開封第一講書人閱讀 167,755評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長疹启。 經(jīng)常有香客問我古程,道長,這世上最難降的妖魔是什么喊崖? 我笑而不...
    開封第一講書人閱讀 59,528評論 1 296
  • 正文 為了忘掉前任挣磨,我火速辦了婚禮,結果婚禮上荤懂,老公的妹妹穿的比我還像新娘茁裙。我一直安慰自己,他們只是感情好节仿,可當我...
    茶點故事閱讀 68,526評論 6 397
  • 文/花漫 我一把揭開白布晤锥。 她就那樣靜靜地躺著,像睡著了一般廊宪。 火紅的嫁衣襯著肌膚如雪矾瘾。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,166評論 1 308
  • 那天箭启,我揣著相機與錄音壕翩,去河邊找鬼。 笑死傅寡,一個胖子當著我的面吹牛放妈,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荐操,決...
    沈念sama閱讀 40,768評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼大猛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了淀零?” 一聲冷哼從身側響起挽绩,我...
    開封第一講書人閱讀 39,664評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驾中,沒想到半個月后唉堪,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體模聋,經(jīng)...
    沈念sama閱讀 46,205評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,290評論 3 340
  • 正文 我和宋清朗相戀三年唠亚,在試婚紗的時候發(fā)現(xiàn)自己被綠了链方。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,435評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡灶搜,死狀恐怖祟蚀,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情割卖,我是刑警寧澤前酿,帶...
    沈念sama閱讀 36,126評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站鹏溯,受9級特大地震影響罢维,放射性物質發(fā)生泄漏。R本人自食惡果不足惜丙挽,卻給世界環(huán)境...
    茶點故事閱讀 41,804評論 3 333
  • 文/蒙蒙 一肺孵、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧颜阐,春花似錦平窘、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,276評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至猿棉,卻和暖如春磅叛,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背萨赁。 一陣腳步聲響...
    開封第一講書人閱讀 33,393評論 1 272
  • 我被黑心中介騙來泰國打工弊琴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人杖爽。 一個月前我還...
    沈念sama閱讀 48,818評論 3 376
  • 正文 我出身青樓敲董,卻偏偏與公主長得像,于是被迫代替她去往敵國和親慰安。 傳聞我的和親對象是個殘疾皇子腋寨,可洞房花燭夜當晚...
    茶點故事閱讀 45,442評論 2 359

推薦閱讀更多精彩內(nèi)容