rust04所有權(quán)

所有權(quán)指涵蓋的范圍有: 變量作用域、垃圾處理機(jī)制、引用,圍繞著幾種行為來闡述所有權(quán)概念。

?

變量作用域(Scope)

任何編程語言中都存在變量作用域的概念, Rust中的變量作用域與其他編程語言也基本一致;作用域大致上會分為: 全局作用域, 函數(shù)內(nèi)作用域.

全局作用域

在下面這段代碼中, PROGRAM常量和main函數(shù)就是一個全局作用域; 反過來講就是當(dāng)前程序代碼中,全局作用域擁有兩個對象, 第一個對象是 PROGRAM 常量, 第二個對象是 main 函數(shù)。

const PROGRAM: &'static str = "Rust";

fn main() {
    println!("{}", PROGRAM);
}


# 作用域的形式可以這么理解, global_scope中有兩個對象.
global_scope = {
    "const PROGRAM": "Rust"
    "fn main": "println!({}, PROGRAM)"
}
函數(shù)內(nèi)作用域

變量不能let(定義)在全局作用域中, 所以全局作用域能做的事情并不多: 定義常量、定義函數(shù)、引用其他模塊文件; 更多的合法操作實在函數(shù)作用域中完成: 定義變量、打印變量、邏輯計算、邏輯判斷、函數(shù)調(diào)用和執(zhí)行等.

const PROGRAM: &'static str = "Rust";

fn main() {
    let s = "abc";                      // 定義變量
    let sf = simple_function();         // 執(zhí)行函數(shù)
    let sum = 10 + 15;                  // 邏輯計算
    if sum > 0 {                        // 邏輯判斷
        println!("{} {} {}", PROGRAM, s, sum);  // 打印常量和變量
    }
}

fn simple_function() {
    let sf = "Simple Function";         // 定義變量
    sf                                  // return 變量
}


# 作用域的形式可以這么理解, global_scope中有三個對象, 其中
# main對象中又有一個二級作用域, simple_function對象中也有一個
# 二級作用域.
global_scope = {                        // 作用域

    "const PROGRAM": "Rust",
    
    "main": {                           // 作用域
        "let s": "abc",
        "let sf": "Simple Function",
        "let sum": 25,
    },
    
    "simple_function": {                // 作用域
        "let sf": "Simple Function"
    }
}

?
?

垃圾處理機(jī)制

像其他具備GC回收機(jī)制編程語言一樣,當(dāng)程序執(zhí)行完成并跳出某個作用域(通常指的是一個函數(shù))時,該作用域中的所有變量將會失效(被回收);除此之外, Rust對垃圾回收這件事情上還具備其他的能力和行為, 例如: 當(dāng)需要對存儲在堆(Heap)中的數(shù)據(jù)進(jìn)行復(fù)制時, 被賦值對象將具備賦值對象的數(shù)據(jù),而賦值對象將會被回收。

離開作用域時回收數(shù)據(jù)
fn simple_function() {
    let sf = "Simple Function";    // sf變量開始生效
    println!("{}", sf);            // sf變量仍然生效
}                                  // sf變量不再生效

fn main() {
    simple_function();             // 當(dāng)該函數(shù)執(zhí)行完成后, sf變量就會被回收
    println!("{}", sf);            // 報錯: sf變量不存在.
}
變量傳遞后即刻失效

fn simple_function(sf: String) {
    println!("simple_function: {}", sf);
}

fn main() {
    let s = String::from("hello");
    simple_function(s);
    println!("main: {}", s);
}



# 報錯
Compiling ownership v0.1.0 (file:///opt/learn_rust/ownership)
error[E0382]: use of moved value: `s`
  --> src/main.rs:10:26
   |
9  |     simple_function(s);
   |                     - value moved here
10 |     println!("main: {}", s);
   |                          ^ value used here after move
   |
   = note: move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait

通過return讓它重回原作用域

fn simple_function(sf: String) -> String {  // -> String 聲明返回值類型
    println!("simple_function: {}", sf);
    sf
}

fn main() {
    let s = String::from("hello");
    let s = simple_function(s);     // 利用返回值, 重新定義變量.
    println!("main: {:?}", s)       
}

數(shù)據(jù)存儲在棧上時, 變量再賦值不會回收原變量
fn main() {
    let a = 10;                 // rust會將固定不變的值存儲在棧(Stack)上.
    let b = a;                  // rust對棧上的數(shù)據(jù)默認(rèn)采取深復(fù)制.
    println!("{} {}", a, b);
}

fn main() {
    let a = "abc";              // 與上面是一樣的.
    let b = a;                  
    println!("{} {}", a, b);
}
當(dāng)變量存儲再堆上時, 變量再賦值就會回收原變量(所有權(quán)轉(zhuǎn)移)
fn main() {

    // rust會將這種未知大小的數(shù)據(jù)存儲在堆(Heap)上.
    // 因為String::from這種結(jié)構(gòu)的數(shù)據(jù)支持push_str
    // 來擴(kuò)充它的大小, 因此從本質(zhì)上來講是未知大小.
    let a = String::from("hello");  
    
    // rust對堆上的數(shù)據(jù)默認(rèn)采取移除上一個變量創(chuàng)建
    // 新變量的機(jī)制, 這種做法在術(shù)語上叫做所有權(quán)轉(zhuǎn)移.
    let b = a;                  
    
    // 這里會報錯, a變量已被移除
    println!("{} {}", a, b)     
}


# 報錯信息
Compiling ownership v0.1.0 (file:///opt/learn_rust/ownership)
error[E0382]: use of moved value: `a`
  --> src/main.rs:10:23
   |
7  |     let b = a;
   |         - value moved here
...
10 |     println!("{} {}", a, b)
   |                       ^ value used here after move
   |
   = note: move occurs because `a` has type `std::string::String`, which does not implement the `Copy` trait

?
?

引用(reference)

不可變更引用(默認(rèn))
fn main() {
    let a = 10;
    
    // b變量是一個指針, 它并沒有實際數(shù)據(jù)的所有權(quán).
    let b = &a;
    
    // 引用是在棧上創(chuàng)建一個指針指向棧數(shù)據(jù).
    // 它比在棧上深復(fù)制更輕量.
    println!("{} {}", a, b)     
}
可變引用
fn main() {
    let mut a = "hello";
    a + "b"
    println!("{}", a)
}
引用的注意事項
可變對象不能被多次引用, 這會導(dǎo)致數(shù)據(jù)競爭.
fn main() {
    let mut a = 10;
    let b = &mut a;
    let c = &mut a;
}


# 報錯
Compiling ownership v0.1.0 (file:///opt/learn_rust/ownership)
error[E0499]: cannot borrow `a` as mutable more than once at a time
  --> src/main.rs:18:18
   |
17 |     let b = &mut a;
   |                  - first mutable borrow occurs here
18 |     let c = &mut a;
   |                  ^ second mutable borrow occurs here
19 | }

可變對象被可變引用之后, 再次引用會導(dǎo)致數(shù)據(jù)不一致.
fn main() {
    let mut a = 10;

    // 可變對象被可變引用走了
    let b = &mut a;

    // 這里會報錯, 因為數(shù)據(jù)狀態(tài)任何時刻都可能會改變,
    // 這是不可預(yù)期的, 所以rust不允許這種情況的出現(xiàn).
    println!("{} {}", a, b)
}

可變對象被可變引用之后,數(shù)據(jù)不一致的解決辦法
fn simple_function(sf: &mut String) -> String {
    sf.push_str(" world!");
    let new_sf = sf.clone();
    new_sf
}

fn main() {
    let mut a = String::from("hello");

    // 站在變量的角度來講: &mut a 的專業(yè)術(shù)語為<可變引用>
    // &mut a 當(dāng)做參數(shù)傳遞給函數(shù)時, 專業(yè)術(shù)語為<可變借用>
    let b = simple_function(&mut a);  

    println!("a: {}\nb: {}", a, b)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,765評論 18 399
  • 1.項目經(jīng)驗 2.基礎(chǔ)問題 3.指南認(rèn)識 4.解決思路 ios開發(fā)三大塊: 1.Oc基礎(chǔ) 2.CocoaTouch...
    陽光的大男孩兒閱讀 5,031評論 0 13
  • 重點掌握 3 類對象和方法 對象就是一個物體 類的獨特存在就是一個實例,對實例進(jìn)行操作叫做方法。方法可以應(yīng)用于類或...
    Coder大雄閱讀 1,281評論 0 2
  • 當(dāng)化妝品專柜的小姑娘嗲聲嗲氣的喚我聲"姐 ",當(dāng)美容院的心機(jī)大媽喋喋不休的吐槽我的法令紋。我覺得我的閃閃玻璃心瞬間...
    紫果凍閱讀 388評論 0 1
  • 總有一首歌能唱出你的心聲,總有一句話會觸動內(nèi)心的柔軟。誰的青春不留點遺憾呢? “真的想寂寞的時候有個伴,日子再忙也...
    總能長大的蒲公英閱讀 279評論 0 3