在上一篇的基础上,我们加一层Option的包裹。还是先定义struct:
#[derive(Debug)]
struct Point {
x: Box<i32>,
y: i32,
}
下列代码不可编译:
fn main() {
let a = Some(Point {
x: Box::new(5),
y: 5,
});
let b = a.as_ref();
let c = b.unwrap();
let d = *c; // Error! move occurs because `*c` has type `Point`, which does not implement the `Copy` trait
println!("c = {:?}", c);
println!("b = {:?}", b);
println!("a = {:?}", a);
}
变量b为a调用as_ref()后获得的新Option,类型为Option<&Point>; c 为b unwrap后的值,类型为&Point,d尝试对c进行解引用,违反了所有权规则,编译错误。
如果修改为as_mut(), 会报类似的错误,如下,原因也类似:
let mut a = Some(Point {
x: Box::new(5),
y: 5,
});
let b = a.as_mut();
let c = b.unwrap();
let d = *c; // Error! move occurs because `*c` has type `Point`, which does not implement the `Copy` trait
直接使用获得的引用或可变引用,是可以的:
fn main() {
let mut a = Some(Point {
x: Box::new(5),
y: 5,
});
let b = a.as_mut();
let c = b.unwrap();
c.x = Box::new(10);
println!("c = {:?}", c);
// println!("b = {:?}", b);
println!("a = {:?}", a);
}
上述代码对c.x的改变,直接改变了a的值,输出如下:
c = Point { x: 10, y: 5 }
a = Some(Point { x: 10, y: 5 })
或:
fn main() {
let mut a = Some(Point {
x: Box::new(5),
y: 5,
});
let b = a.as_mut();
let c = b.unwrap();
// c.x = Box::new(10);
*c.x += 10;
// or
// let d = &mut c.x;
// **d += 10;
println!("c = {:?}", c);
// println!("b = {:?}", b);
println!("a = {:?}", a);
}
输出:
c = Point { x: 15, y: 5 }
a = Some(Point { x: 15, y: 5 })
最后,对于之前几篇学习的几个主要结论总结一下:
- 对于struct类型,如果成员未实现Copy trait,可以将其部分或全部成员的所有权转移出去;
- struct类型的(可变)引用,无法转移成员的所有权;(别小看这个,这是不同于C/C++编写链表时的坑之一)
- struct类型的(可变)引用,不能解引用;其成员的(可变)引用,如果成员未实现Copy trait,也不能解引用;(参考笔记(10))
- Option类型可以通过unwrap、take 分别获取包含对象的值的所有权,通过as_ref/as_mut获取包含对象的引用或可变引用;
- 对引用可以继续引用,可变引用类似。这类似于C语言中的指针的指针;(笔记(8)中有实验)
- struct支持分别对其不同成员同时进行可变引用,Vec则不支持。(笔记(6)中有实验)
- 不可变引用不能改变其指向变量的值,其本身(指针本身)可以通过copy进行复制;(笔记(6)中有实验)
- 可变引用可以改变指向变量的值,可变引用这个变量本身(指针本身)未实现Copy trait,其赋值是move 操作。(笔记(6)中有实验)
暂时到这里吧,以后如果有新的发现再补充。