iT邦幫忙

2025 iThome 鐵人賽

DAY 25
0

1. Ownership:

Rust 裡沒有 delete,因為資源會自己走完生命週期

在 C++ 裡,你可以這樣:

string* s = new string("hello");
cout << *s;
delete s; // 忘記就爆

Rust 規則是:

每個值有唯一的擁有者(owner),離開作用域就自動被釋放。

fn main() {
    let s = String::from("hello");
    println!("{s}");
} // 離開這裡,s 自動 drop()

不用 delete,因為 Rust 的 RAII(Resource Acquisition Is Initialization)是語言級的強制規範,所有資源(不只是記憶體,還有檔案、socket、鎖)都在離開作用域時自動清理。

2. Borrow Checker:

C++ 會允許你這樣做:

int* p;
{
    int x = 10;
    p = &x; // 合法
}
cout << *p; // boom

Rust 直接在編譯期攔下來:

let r;
{
    let x = 10;
    r = &x; // error: `x` does not live long enough
}
println!("{r}");

因為 Rust 有一套生命週期(lifetime)分析器,能在編譯時判斷指標(實際上是 reference)會不會被懸掛。

這個機制是 Borrow Checker 在背後做的,它的邏輯大致是:

  • 同一時間要嘛有多個不可變借用 &T,要嘛只有一個可變借用 &mut T
  • 任何引用不能活得比來源久。

C++ 的 std::unique_ptr 只是個類型包裝,而 Rust 的 ownership/borrow 則是語法規則。

3. Option 與 Result:取代 nullptrthrow

C++ 裡常見這樣的錯誤傳遞方式:

Foo* find_user(int id) {
    if (id < 0) return nullptr;
    return new Foo(id);
}

然後呼叫端忘記檢查 nullptr。

Rust 沒有 null,取而代之的是 Option<T>

fn find_user(id: i32) -> Option<Foo> {
    if id < 0 { None } else { Some(Foo { id }) }
}

呼叫端一定得處理兩種情況:

if let Some(user) = find_user(10) {
    println!("找到使用者 {:?}", user);
} else {
    println!("沒找到");
}

錯誤也一樣,用 Result<T, E> 取代 throw

fn divide(a: f64, b: f64) -> Result<f64, String> {
    if b == 0.0 { Err("除以零".into()) } else { Ok(a / b) }
}

fn main() -> Result<(), String> {
    let x = divide(10.0, 2.0)?; // `?` 會自動往外丟 Err
    println!("結果 = {x}");
    Ok(())
}

而這種傳遞機制就會處理每一個錯誤不會漏掉。

4. Trait:比虛擬繼承更靈活的行為合約

C++ 用繼承表達多型:

class Shape {
public:
    virtual void draw() = 0;
};
class Circle : public Shape {
public:
    void draw() override { cout << "Circle\n"; }
};

Rust 用 Trait 表達「誰能做什麼」:

trait Drawable {
    fn draw(&self);
}

struct Circle;
struct Square;

impl Drawable for Circle {
    fn draw(&self) { println!("畫圓"); }
}
impl Drawable for Square {
    fn draw(&self) { println!("畫方"); }
}

fn render<T: Drawable>(obj: &T) {
    obj.draw();
}

Trait 沒有繼承樹、沒有 vtable 開銷,每個實作在編譯期就展開成具體函式呼叫(zero-cost abstraction)


5. Move vs Copy:顯式擁有權轉移

在 C++ 裡:

std::string s1 = "hi";
std::string s2 = s1; // 呼叫拷貝建構子

Rust 裡:

let s1 = String::from("hi");
let s2 = s1; // move,s1 不可再用
// println!("{s1}"); // error

如果型別很輕(如 i32、f64),則自動 Copy:

let a = 10;
let b = a; // OK,a 繼續可用

Rust 讓每個型別都明確表達「我能被 Copy 嗎?」這樣能避免不小心深拷貝整個結構體或造成記憶體多重釋放。

6. 沒有 GC,但也不用手動管理

Rust 它沒有 Garbage Collector,也不需要。釋放時機在編譯期就能決定,這意味著:

  • 無停頓(no GC pause);
  • 零 runtime overhead;
  • 保留類似 C++ 的可預測效能。

上一篇
Day 24|Borrow Checker:我不相信你
下一篇
Day 26|TransferableStructured CloneSharedArrayBuffer
系列文
把前端加速到天花板:Rust+WASM 即插即用外掛26
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言