起因
看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函數聲明順序可以隨意)