引用的操作

引用的赋值

在 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. 要么其值 是一个有效的引用. 这个写法不会占用额外的内存.