症状
出现 error[E0499]: cannot borrow value as mutable more than once at a time 或 error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable;通常在循环内新增调用、跨 await 持有引用或方法接收 &mut self 时出现。
诊断
阅读完整的借用检查错误,包括两个 span:
cargo check
错误显示第一次借用、冲突借用以及让第一次借用保持存活的生命周期;通常较长的那段需要缩短。用 cargo check --message-format=short 查看精简输出,删除无关调用,构造最小复现。cargo clippy --all-targets 常会建议拆分借用、克隆值或调整迭代器。
根因
Rust 的别名规则允许一个可变引用或任意多个不可变引用同时存在。代码让某个借用存活得比编译器预期更久,于是第二次借用与它重叠。
修复
先计算值、结束引用,再进行可变借用:
// ❌ immutable borrow of items is alive during push
let first = items.first();
items.push(42);
println!("{first:?}");
// ✅ finish using the borrow before mutating
let first = items.first().copied();
items.push(42);
println!("{first:?}");
也可以拆分结构体字段,让编译器看到不相交的借用;把变更移入拥有数据的方法;用索引替代引用;或在确需共享可变时使用 RefCell(单线程)或 Mutex/RwLock(多线程),并接受运行时开销。
验证
cargo check、cargo test 和 cargo clippy -- -D warnings 通过;确认变更在预期位置可见,没有用克隆悄悄改变语义;如果引入内部可变性,测试应覆盖借用冲突与 panic 行为。
风险提示
用 unsafe、到处 clone() 或 RefCell 来强行绕过借用检查会改变性能或运行时行为,并掩盖真正的所有权设计问题。优先重构借用,只在设计确实需要共享可变状态时使用运行时检查。