iT邦幫忙

2021 iThome 鐵人賽

DAY 21
0

所有權可以說是Rust核心概念,這讓Rust不需要垃圾回收(garbage collector)就可以保障記憶體安全。Rust的安全性和所有權的概念息息相,因此理解Rust中的所有權如何運作是非常重要的

所有權的規則

  • Rust 中每個數值都會有一個變數作為它的擁有者(owner)
  • 同時間只能有一個擁有者。
  • 當擁有者離開作用域時,數值就會被丟棄。

變數作用域

用下面這段程序描述變數范圍的概念

{
    // 在宣告以前,變數s無效
    let s = "hello";
    // 這裡是變數s的可用範圍
}
// 變數範圍已經結束,變數s無效

變數作用域是變數的一個屬性,其代表變數的可使用範圍,默認從宣告變數開始有效直到變數所在作用域結束。

記憶體與分配

定義一個變數並賦予值,這個變數的值存在記憶體中,例如需要用戶輸入的一串字串由於長度的不確定只能存放在堆(heap)上,這需要記憶體分配器在執行時請求記憶體並在不需要時還給分配器

在擁有垃圾回收機制(garbage collector, GC)的語言中,GC會追蹤並清除不再使用的記憶體,如果沒有GC的話則需要在不使用時顯式的呼叫釋放記憶體

例如C語言

{    
    char *s = strdup("hello");    
    free(s); *// 釋放s資源*
}

Rust選擇了一個不同的道路,當變數在離開作用域時會自動釋放例如下面

{
    let s = String::from("hello"); // s 在此開始視為有效
    // 使用 s
} // 此作用域結束,釋放s變數     

當變數離開作用域(大括號結束)時會自動呼叫特殊函示drop來釋放記憶體

變數與資料互動的方式

移動(Move)

變數可以在Rust中以不同的方式與相同的資料進行互動

let x = 100;
let y = x;

這個代碼將值100綁定到變數x,然後將x的值復制並賦值給變數y現在棧(stack)中將有兩個值100。此情況中的數據是"純量型別"的資料,不需要存儲到堆中,僅在棧(stack)中的資料的"移動"方式是直接複製,這不會花費更長的時間或更多的存儲空間。"純量型別"有這些:

  • 所有整數類型,例如 i32 、 u32 、 i64 等
  • 布爾類型 bool,值為true或false
  • 所有浮點類型,f32和f64
  • 字符類型 char
  • 僅包含以上類型數據的元組(Tuples)

現在來看一下非純量型別的移動

let s1 = String::from("hello");
let s2 = s1;

String物件的值"hello"為不固定長度長度型別所以被分配到堆(heap)

當s1賦值給s2,String的資料會被拷貝,不過我們拷貝是指標、長度和容量。我們不會拷貝指標指向的資料

前面説當變數超出作用域時,Rust自動調用釋放資源函數並清理該變數的記憶體。但是s1和s2都被釋放的話堆(heap)區中的"hello"被釋放兩次,這是不被系統允許的。為了確保安全,在給s2賦值時 s1已經無效了

let s1 = String::from("hello");
let s2 = s1; 
println!("{}, world!", s1); // 會發生錯誤 s1已經失效了

克隆(clone)

正常情況下Rust在較大資料上都會以淺拷貝的方式,當然也有提供深拷貝的method

let s1 = String::from("hello");
let s2 = s1.clone();
println!("{} {}", s1, s2);

輸出
hello hello

上一篇
Rust-定義泛型結構
下一篇
Rust-所有權(二)
系列文
Rust 新手村30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言