引用的操作

引用的赋值

在 C++ 中, 引用在初始化之后, 其指向的内存地址便不再能被修改. 在 Rust 中, 却不是这样的, 引用可以再被指向别的地址:

#![allow(unused)] fn main() { let x = 42; let y = 3; let mut r = &x; if y > 0 { r = &y; } }

这里, 我们使用 let mut r = &x; 因为要修改 r 指向的地址, 所以要给它加 mut 来修饰.

比较两个内存是否是同一个地址, 可以使用 std::ptr::eq().

创建引用的引用

解引用 Dereference

尽管引用是一种指针, 但因为它使用很频繁, Rust 在 . 操作符被使用时, 若有必要会 自动直接访问指针所指向的内存 deref 而不需要像 C 语言那样使用 *ref. 这个 功能被称为 implicit dereference`.

同时, 如有必要, .操作符还会隐式地借用其左操作值的引用:

#![allow(unused)] fn main() { let mut v = vec![1, 3, 2]; v.sort(); (&mut v).sort(); }

其中 v.sort() 被隐式去转换成了 (&mut v).sort().

#![allow(unused)] fn main() { let ref value = 42; }

等同于以下写法:

#![allow(unused)] fn main() { let value = &42; }

match 进行模式匹配时, 可以使用 refref mut 来从 struct/tuple 中 解析出需要的元素:

#[derive(Debug)] struct Point { x: i32, y: i32, } fn main() { let mut p = Point { x: 0, y: 5 }; match p { Point { x: 0, ref mut y } => *y = 3, _ => println!("Do nothing!"), } println!("p: {:?}", p); }

引用之间的比较

以下示例中, assert!(ref_x == ref_y); 进行的是值的比较; 而 assert!(!std::ptr::cmp(ref_x, ref_y)); 则比较了两个引用本身的内存地址, 所以它们是不相等的.

fn main() { let x = 42; let y = 42; let ref_x = &x; let ref_y = &y; assert!(ref_x == ref_y); assert!(!std::ptr::eq(ref_x, ref_y)); }

引用永远是有效的

引用不能是空指针或者别的无效值, 它们在编译期就已经确认了一直是有效的.

Option<&T> 表示可以是无效引用, 其值为 None, 类似于 C++ 中的 nullptr. 要么其值 是一个有效的引用. 这个写法不会占用额外的内存.