blog.dopana

Back

这是Rust基础系列的第6篇文章。所有权保证了内存安全,但如果频繁转移所有权会使代码变得繁琐。“借用”(Borrowing)允许在不获取所有权的情况下访问数据。

使用引用进行借用#

引用允许你指向某个值而不获取其所有权。使用 & 运算符创建引用:

fn calculate_length(s: &String) -> usize {
    s.len()
}

fn main() {
    let s1 = String::from("hello");
    let len = calculate_length(&s1);
    println!("'{s1}' 的长度是 {len}。");
}
rust

由于 calculate_length 接受 &String 引用,s1 被借用而不是被移动。函数调用后 s1 依然有效。

可变引用#

默认情况下,引用是不可变的。要修改借用的数据,需使用可变引用 &mut

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

fn main() {
    let mut s = String::from("hello");
    change(&mut s);
    println!("{s}");
}
rust

创建可变引用前,原变量必须也使用 mut 声明。

借用的核心规则#

Rust在编译期严格执行以下规则以防止数据竞争:

在同一时间内,你要么拥有任意多个不可变引用 (&T),要么拥有唯一个可变引用 (&mut T),但不能两者兼有。

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

let r1 = &s; // OK
let r2 = &s; // OK
// let r3 = &mut s; // 错误:已存在不可变引用,无法再借用为可变引用
println!("{r1} 与 {r2}");
rust

这种“别名与可变性互斥”的规则保证了在程序其他部分读取数据时,数据绝不会被意外修改。

切片#

切片是对集合中一段连续元素序列的引用,而不是对整个集合的引用。

字符串切片#

字符串切片 (&str) 引用 String 的一部分:

let s = String::from("hello world");

let hello: &str = &s[0..5];
let world: &str = &s[6..11];
rust

字符串字面值 ("hello") 本质上就是指向已编译二进制数据的字符串切片。

数组切片#

切片同样适用于数组与向量:

let a = [1, 2, 3, 4, 5];
let slice: &[i32] = &a[1..3];

assert_eq!(slice, &[2, 3]);
rust

总结#

通过引用(&&mut)借用数据可以安全地共享数据。切片(&str&[T])提供了对序列的灵活只读视图。本系列的下一篇文章将探讨“结构体”(Struct)。

参考资料#