先定义一个struct如下:
#[derive(Debug)]
struct Point {
x: i32,
y: i32,
}
但我们从最简单的类型开始。我们知道对于简单类型来说,其值是可以copy的,所以下方代码没有任何问题:
fn main() {
let a = 5;
let b = &a;
let mut c = *b; // copy '*b' to c; So c's value is 5.
c += 10;
println!("{:?}", c);
println!("{:?}", b);
println!("{:?}", a);
}
改变c的值,对a、b没有影响,输出为:
15
5
5
可变引用可以改变原变量的值,下段代码之前运行过:
fn main() {
let mut a = 5;
let b = &mut a;
*b += 10;
println!("b = {:?}", b);
println!("a = {:?}", a);
}
输出为:
b = 15
a = 15
那么对于复合型的值呢?不可以对借用进行解引用,因为借用不拥有数据的所有权,所以不能将其借用的数据转移到另一个变量中去。下面带注释行的代码不可编译:
fn main() {
let a = Point { x: 5, y: 5 };
let b = &a;
let c = *b; // Error! cannot move out of `*b` which is behind a shared reference
}
如果将最后一行改为:
let c = (*b).x; // copy '(*b).x' to c;
// or
let c = b.x; // copy '(*b).x' to c;
则是可行的,因为x为简单类型;如果x未实现copy trait的话,也不行,这个在笔记(6)中学过。同样,在上面这个例子中,将不可变引用全部改为mut,也不行,原因还是因为借用不拥有变量(或数据)的所有权。下面带注释的行同样不可编译:
let mut a = Point { x: 5, y: 5 };
let b = &mut a;
let c = *b; // Error! cannot move out of `*b` which is behind a mutable reference.
如果引用struct中的一个值,能被解引用吗?先看简单值:
fn main() {
let a = Point { x: 5, y: 5 };
let b = &a.x;
let mut c = *b; // copy *b to c;
c += 20;
println!("c = {:?}", c);
println!("b = {:?}", b);
println!("a = {:?}", a);
}
输出:
c = 25
b = 5
a = Point { x: 5, y: 5 }
可以,但可以看出,简单值还是copy的,对c的改变不影响a。那么值的类型为智能指针类型呢?我们将Point的成员x的类型改为Box<i32>类型试试:
let a = Point {
x: Box::new(5),
y: 5,
};
let b = &a.x;
let c = *b; // Error! move occurs because `*b` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
答案是不行!*b代表着a的成员x, 其类型是Box类型,未实现Copy trait。因为b为a.x的借用,b不拥有a.x的所有权,所以也不能将*b(也就是a.x)移动到c。
最后:
1、对于复合类型(如struct)的(可变)引用不可解引用;
2、对于复合类型的未实现Copy trait的成员的(可变)引用也不可以解引用。
3、对于1、2两点,可以连续(可变)引用。这个也在笔记(6)中提到过。
之所以啰啰嗦嗦反反复复的写这么多,是因为对于复合数据类型如struct在引用的情况下,在实际应用中所有权会带来很多意想不到的问题。尤其是和Option等结合起来的时候。因为上一篇学到Option的两个方法as_ref() 和 as_mut(),得到的分别是其包含值的引用和可变引用。这个问题本来是在准备写下一篇关于链表节点的操作时临时想到的,又花了点功夫掰扯了一下。