iT邦幫忙

2023 iThome 鐵人賽

DAY 18
0

今天應該就進入到所有權的尾聲,會為前幾天的文章內容做一些補充

move 多個變數時

接下來要補充的是,當我們要同時 move 給多個變數,該怎麼做

沿用前兩天的例子

fn main() {
    let drink1 = String::from("Milk Tea");

    let drink2 = drink1;
    let drink3 = drink1;
}

我們來執行一下,出現了錯誤訊息

來回想一下所有權的規則

  1. 每個值都會有一個 owner
  2. 每個值一次只能有一個 owner
  3. 當 owner 離開 scope ,值就會消失

每個值一次只能有一個 owner ,

我們在 move 的時候會將所有權給 drink2,但如果接下來要給其他變數,這樣是不可能的

以生活例子來說, drink1 現在有一杯奶茶,他要將這杯奶茶給 drink2

給了 drink2 後, drink1 手上就沒東西了,他沒辦法再給 drink3

> cargo run

error[E0382]: use of moved value: `drink1`
 --> src/main.rs:5:18
  |
2 |     let drink1 = String::from("Milk Tea");
  |         ------ move occurs because `drink1` has type `String`, which does not implement the `Copy` trait
3 |
4 |     let drink2: String = drink1;
  |                          ------ value moved here
5 |     let drink3 = drink1;
  |                  ^^^^^^ value used here after move
  |
help: consider cloning the value if the performance cost is acceptable
  |
4 |     let drink2: String = drink1.clone();
  |                                ++++++++

For more information about this error, try `rustc --explain E0382`.
warning: `hello_world` (bin "hello_world") generated 2 warnings
error: could not compile `hello_world` (bin "hello_world") due to previous error; 2 warnings emitted

那解法是什麼?我們可以用 Clone 這個 trait

Clone 這個 trait 會幫我們複製 drink1 一模一樣的值出來,

而他們指向的記憶體位址是不一樣的,

可以把它想像成是做出一個複製奶茶出來,

而原本的奶茶所有權還是在 drink1 手上

複製出來的奶茶所有權在 drink2 手上

drink2 就可以將這杯複製奶茶給 drink3

fn main() {
    let drink1 = String::from("Milk Tea");

    let drink2: String = drink1.clone();
    let drink3 = drink2;

    println!("drink1 is {}", drink1);
    println!("drink3 is {}", drink3);
}

> cargo run

drink1 is Milk Tea
drink3 is Milk Tea

那 drink2 呢? drink2 將值的所有權給了 drink3

所以之後 drink2 就不會再有複製奶茶的所有權了

fn main() {
    let drink1 = String::from("Milk Tea");

    let drink2: String = drink1.clone();
    let drink3 = drink2;

    println!("drink1 is {}", drink1);
    println!("drink2 is {}", drink2);
    println!("drink3 is {}", drink3);
}
> cargo run

8 |     println!("drink2 is {}", drink2);
  |                              ^^^^^^ value borrowed here after move

不過基本型別就不是使用 move 以及 clone trait

我們來介紹一下基本型別

基本型別

基本型別像是 integerFloatBoolean

他們的 value 是固定的,就只會存在於 Stack 中

如果我們今天要將一個基本型別變數的值,給另一個變數指向,

實際上是使用了 copy 這個 trait 將值進行複製,

這邊就不會有所有權的轉移問題,

因為 number1 的值並沒有轉移給 number2,

而是用 copy 的方式,讓 number2 的值跟 number1 一樣

fn main() {
    let number1 = 1;
    let number2 = number1;

    println!("number1 is {}", number1);
    println!("number2 is {}", number2)
}

我們來看一下執行結果

> cargo run

number1 is 1
number2 is 1

上一篇
Day 17 Ownership part 3
下一篇
Day 19 生命週期 part 1
系列文
成為程式界的 F1 賽車手,用 30 天認識 Rust 30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言