Rust中多共享引用如何安全访问非Copy/Clone类型值?
我是Rust新手,已读完《The Book》,希望深入理解该语言中引用的底层机制。
我知道引用是一种指针类型,解引用时会指向内存中的某个值:
let x = 5; let y = &x;
在这个示例中,y是指向x内存地址的指针,因此y的类型和值与x不同:
assert_eq!(y, x); // 编译失败,因为assert_eq!未实现`&{integer} == {integer}`的比较逻辑
- 引用与其指向的值并非同一事物。
但使用*操作符对y解引用后,就能获取它指向的值,以下代码可以正常编译:
assert_eq!(*y, x);
不过解引用操作存在一个问题:如果将解引用后的值赋值给新变量,会触发所有权转移(对于未实现Copy trait的类型):
#[derive(Debug)] struct Point { x: i32, y: i32 } let x = Point {x:1, y:2}; let y = &x; let z = *y; // 编译失败,因为`*y`的类型为`Point`,未实现`Copy` trait,触发所有权转移
- 为该类型实现
Copytrait后,Rust会创建值的副本,并将副本的所有权转移给新变量,从而解决编译错误。
核心问题
对于未实现Copy或Clone trait的类型,Rust如何通过引用访问其值,同时避免解引用操作获取值的所有权,导致原变量的其他共享引用失效?
可运行示例
#[derive(Debug)] struct Point { x: i32, y: i32 } let x = Point {x:1, y:2}; let y = &x; let z = &x; fn print_point(a: &Point){ println!("{a:#?}") } println!("Printing y"); print_point(y); println!("Printing x"); println!("{x:#?}"); println!("Printing z"); print_point(z);
解决方案与原理
要避免解引用触发所有权转移,核心是不要将解引用后的值赋值给拥有所有权的新变量,而是通过以下方式基于引用直接访问值:
传递引用给函数
示例中的print_point函数接收&Point类型的参数,传递的是引用本身的副本(引用默认实现了Copytrait),不会触及原值的所有权,因此原变量x和其他引用z都能正常使用。利用自动解引用(Deref Coercion)访问内容
Rust会自动处理引用的多层解引用,比如对于&Point类型的变量y,你可以直接写y.x来访问字段,无需手动写(*y).x。这种操作只是临时访问值的内容,不会转移所有权。临时解引用用于操作而非赋值
如果只是临时使用解引用后的值(比如作为打印参数、计算输入),而非赋值给新变量,也不会触发所有权转移。例如println!("{:#?}", *y),这里的*y是临时借用,执行完后所有权仍属于原变量。
本质上,Rust的借用规则保证了共享引用(&T)可以同时存在多个,只要不尝试获取原值的所有权,通过引用就能安全访问值的内容,同时维持内存安全。
内容的提问来源于stack exchange,提问作者TheRoniOne

