编程Rust 后端开发者

解释一下 Rust 中的借用和别名是如何工作的。对可变引用和不可变引用的同时使用有什么限制,编译器如何控制这些限制,以及可能发生什么问题?

用 Hintsage AI 助手通过面试

答案

在 Rust 中,借用是通过引用临时“借用”变量的机制。Rust 区分不可变借用 (&T) 和可变借用 (&mut T)。可以同时存在任意数量的不可变引用,但只能有一个可变引用。不可变引用和可变引用不允许同时存在于同一个对象上。

这个规则保证了在编译阶段不会发生数据竞争,从而使 Rust 对并发编程是安全的。

示例:

let mut value = 5; let r1 = &value; let r2 = &value; // let r3 = &mut value; // 错误:在有 & 的时候不能创建 &mut println!("{} {}", r1, r2); // r3 在 r1/r2 的作用域结束之前是禁止的

诱惑性的问题

问题: 在同一作用域中是否可以创建一个 &mut 引用和任意数量的 & 引用到同一个对象?

典型错误回答: 是的,但前提是它们的生命周期不重叠。

正确答案: 同时不能存在一个可变引用和一个不可变引用指向同一个对象(即使对它们的访问在代码中静态上不重叠),只要一个活着,其他的就被禁止。安全性由借用检查器进行检查。

示例:

let mut x = 10; let y = &x; let z = &mut x; // 错误,y 仍在作用域中 println!("{}", y); // y 在后面需要

由于对主题细微差别的不理解而导致的实际错误示例


故事

在一个大型的并行数据处理项目中,开发者决定使用不可变引用指向一个向量,然后尝试获取一个可变引用进行排序。代码在测试中工作正常,但在重构后因不可变引用的生命周期延长而停止编译。


故事

在内部服务中,通过 &mut 修改结构,同时保存对字段的引用以便稍后发送到其他线程。由于不遵循借用规则,导致数据竞争和崩溃——Rust 仅在编译阶段提供保护,但问题发生在 unsafe 块中,那里没有保证。


故事

API 文档不正确:库同时接受对结构不同字段的 & 和 &mut,但由于别名破坏了不变性,导致与集成该库的服务产生难以捕捉的错误。