iT邦幫忙

2025 iThome 鐵人賽

DAY 8
1

今天主要會講的部分有

  • Lifetime
  • Trait

Lifetime

Lifetime 生命週期是為了確保我們在需要參考的時候,它們都是有效的。

我們前面提到參考的時候,沒有說到每個參考其實都有生命週期,這是決定該參考是否有效的作用域。大多情況下生命週期是隱式且可推導出來的,就像大多情況下型別是可推導出來的。當多種型別都有可能時,我們就得詮釋型別。同樣地,當生命週期的參考能以不同方式關聯的話,我們就得詮釋生命週期。

舉個例子來說

 fn main() {
    let r;

    {
        let x = 5;
        r = &x;
    }

    println!("r: {}", r);
}

在這裡,在內圈的scope,宣告了一個初始值為5的x變數,然後我們把參考賦值給r,在外層我們嘗試要印出這個r的時候就會失敗,因爲x指向的值已經被釋放.

為了檢查出這個錯誤,Rust 編譯器有個借用檢查器(borrow checker)會比較作用域來檢測所有的借用是否有效,如下

fn main() {
    let r;                // ---------+-- 'a
                          //          |
    {                     //          |
        let x = 5;        // -+-- 'b  |
        r = &x;           //  |       |
    }                     // -+       |
                          //          |
    println!("r: {}", r); //          |
}                         // ---------+

這裡,x的生命週期 b 比 r 的生命週期 a 來的短,然後 r 又需要 x 的參考,所以就會有編譯錯誤.

那在考慮底下的這種情況

 fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("最長的字串為 {}", result);
}

在這裡 我們引入了兩個參考,但因為我們有一個判斷式,因為回傳值不固定,也就無法確定回傳值的生命週期,這時候我們就要去定義參考之間的關係來解決這個問題.

程式碼應該要修改如下才行

fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("最長的字串為 {}", result);
}

當我們向 longest 傳入實際參考時,'a 實際替代的生命週期為 x 作用域與 y 作用域重疊的部分。換句話說,泛型生命週期 'a 取得的生命週期會等於 x 與 y 的生命週期中較短的。因為我們將回傳的參考詮釋了相同的生命週期參數 'a,回傳參考的生命週期也會保證在 x 和 y 的生命週期較短的結束前有效。

生命週期也是 Rust 相當重要的一個觀念,可以透過編譯器,多加練習後就能掌握什麼時候需要寫,什麼時候不需要寫了.

Trait

簡單來說,Trait 想像成一種 interface 或是抽象類別 abstract class 的概念,也就是從多種類型中抽取出共性的屬性或方法,並定義這些方法的規範.

底下舉個例子說明

首先我們先定義 trait,輸出是否可以執行

trait Callable {
    fn execute(&self) {
        println!("execute!!!");
    }
}

接著,我們用impl 關鍵字幫 Struct 加上這個方法

impl Callable for Dataclient {}
impl Callable for Tradeclient {}

假設我們已經設定好變數,就可以像底下這樣使用trait中定義好的方法

dataclient.execute();  
tradeclient.execute();

此外,trait還可以做到Polymorphism的效果,例如底下

fn Free(client: &dyn Callable) {
    client.execute();
}

Free(&dataclient); 

因為 dataclient 有這個特徵,所以可以被執行,&dyn 還可以透過 + 去增加更多條件的限制.

今天就先講到這,明天會繼續介紹 Enum 跟 Generics.


上一篇
【Day7】- Rust(Slice, Struct)
下一篇
【Day9】- Rust(Enum, Generics)
系列文
NautilusTrader 架構解析:Rust 在高效能量化交易平台中的角色與優勢22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言