跳转到主要内容
模块 3 · 第 2 课(共 2)课程中的6/14~15 min
模块课程(2/2)

参考文献和借用

在 Rust 中,将所有权来回传递给函数可能很乏味。为了解决这个问题,Rust 使用引用 (&)。

创建对值的引用称为借用。

不可变的引用

通过在类型或变量前面加上 & 符号来声明引用。默认情况下,引用是不可变的:它们允许读取值但不能修改它。

Rust
fn main() {
    let s1 = String::from("hello");

    // We pass a reference to s1, not ownership
    let len = calculate_length(&s1);

    // s1 is still usable here!
    println!("The length of '{}' is {}.", s1, len);
}

fn calculate_length(s: &String) -> usize { // s is a reference to a String
    s.len()
} // Here, s goes out of scope, but since it doesn't own the value, nothing happens

可变引用

如果需要修改借用值,则必须使用带有 &mut 的可变引用。原始变量还必须使用 mut 声明为可变的:

Rust
fn main() {
    let mut s = String::from("hello");

    // We pass a mutable reference
    change(&mut s);

    println!("{}", s); // Prints "hello, world"
}

fn change(some_string: &mut String) {
    some_string.push_str(", world");
}

借款规则

为了防止编译时的内存损坏和数据竞争,Rust 强制执行两条基本规则:

  1. 您可以同时对一个值拥有任意数量的不可变引用 (&T)。
  2. 或者您一次可以只拥有一个对某个值的可变引用 (&mut T)。

您绝对不能在同一范围内混合使用相同值的不可变引用和可变引用:

Rust
let mut s = String::from("hello");

let r1 = &s; // Valid
let r2 = &s; // Valid
// let r3 = &mut s; // COMPILATION ERROR! You cannot create &mut s if s is already borrowed as immutable

参考范围和非词汇生命周期 (NLL)

从历史上看,引用的范围一直持续到创建它的块的末尾。如今,Rust 的编译器更加智能,这要归功于 非词法生命周期 (NLL):引用的作用域在实际使用的最后一行结束,而不一定在块的末尾。

这使得以下代码完全有效:

Rust
let mut s = String::from("hello");
let r1 = &s;
let r2 = &s;
println!("{} and {}", r1, r2); // Last use of r1 and r2. The immutable references expire here!

let r3 = &mut s; // Valid! No active immutable references exist at this point

自己尝试一下

锻炼#rust.m3.l2.e1
尝试:0加载中...

使用 & 符号将 s1 的不可变引用传递给calculate_length函数。

正在加载编辑器...
显示提示

将 `/* TODO \_/`替换为`&s1` 以传递对字符串的不可变引用。

3 次尝试后可用的解决方案

锻炼#rust.m3.l2.e2
尝试:0加载中...

使变量 s 可变(let mut s)并将可变引用(&mut s)传递给更改函数以允许其修改字符串。

正在加载编辑器...
显示提示

使用 `let mut s`代替`let s`并调用`change(&mut s);`。

3 次尝试后可用的解决方案

锻炼#rust.m3.l2.e3
尝试:0加载中...

Declare a variable s containing String::from("Rust"). Create two distinct immutable references r1 and r2 to s, and finally print both references separated by a space using the println! macro.

正在加载编辑器...
显示提示

Assign `let r1 = &s;` and `let r2 = &s;` to obtain two immutable references, then print them with `println!("{} {}", r1, r2);`.

3 次尝试后可用的解决方案