雜記rust的destructuring binding(反結構化綁定)與ownership(所有權)

起因

rust by example看得我想睡覺...突然遇到個關於反結構化綁定的奇怪的特性:

struct Pair(Box<i32>, Box<i32>);

impl Pair {
    fn destroy(self) {
        let Pair(first, second) = self;
        println!("Destroying Pair({}, {})", first, second);
    }
}

fn main() {
    let pair = Pair(Box::new(1), Box::new(2));

    pair.destroy();
    pair.destroy();
}

對pair調用兩次destroy()方法居然會得到錯誤,代碼註釋提示let語句會消耗self,導致self內容被move(移動):

let Pair(first, second) = self;
// 這裏self不再可見

以前聽說過rust的lifetime,ownership,看着樣子估計就是這方面的問題導致的特性

嘗試

我大概理解了它的行爲,let反結構化綁定有點類似於c++的std::move()?於是做了點實驗。

#[derive(Debug)]
struct A{
    x:i32,
    y:i32
}
impl A{
    fn new()->A {
        return A{x:123,y:345};
    }
}
#[allow(unused_variables)]
fn main(){
    let a = A::new();
    let A{x:pointx,y:pointy} = a;
    let A{x:pointx,y:pointy} = a;
}

很遺憾,對a執行兩次反結構化綁定並沒有出現內容被移動。考慮到之前Pair裏面不是primitive type ,那隻能試着引入非primitive type

#[derive(Debug)]
struct A{
    x:i32,
    y:i32
}
struct B{
    val:A
}

impl A{
    fn new()->A {
        return A{x:123,y:345};
    }
}
#[allow(unused_variables)]
fn main(){
    let a = A::new();
    let A{x:pointx,y:pointy} = a;
    let A{x:pointx,y:pointy} = a;

    let b = B{val:a};
    let B{val:res}=b;
    let B{val:res}=b;
}

這次就如之前一樣,對b兩次反綁定得到錯誤,提示b.val已經被移動了。

error[E0382]: use of moved value: `b.val`

原因

然後試着rustc --explain E0382得到了一個很長的解釋:

該錯誤是因爲嘗試使用一個變量,但是變量的內容已經被移到了其他地方。
比如:

struct MyStruct { s: u32 }

fn main() {
    let mut x = MyStruct{ s: 5u32 };
    let y = x;
    x.s = 6;
    println!("{}", x.s);
}

MyStruct是一個沒有被標記爲Copy的類型,當我們let y = x時,x的數據被移了出去。

這也是Rust所有權系統的基礎:一旦出了工作區,變量的值不能被兩個及以上的變量擁有。

有時候我們不需要移動這個值,那麼可以使用引用想另一個函數borrow(借)這個值,同時又不改變它的所有權。比如像下面這樣,不需要把值移動到calculate_length函數裏面,就可以給參數加上引用:

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

    let len = calculate_length(&s1);

    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize {
    s.len()
}

(tips:rust函數聲明順序可以隨意)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章