Rust中为引用实现trait触发E0502借用错误的原因
为什么直接在对象上实现Trait不会触发借用错误,在引用上实现Trait时却抛出
cannot borrow as mutable because it is also borrowed as immutable报错? 针对Vec的原生实现版本可以正常编译:
fn clear_non_empty<T>(collection: &mut Vec<T>) { if !collection.is_empty() { collection.clear() } }
将逻辑泛化为适配任意集合的版本时,如果Trait方法以&self/&mut self为接收者,代码依然可以正常编译:
trait IsEmpty { fn is_empty(&self) -> bool; } trait Clear { fn clear(&mut self); } fn clear_non_empty<'a, Collection: Clear + IsEmpty>(collection: &'a mut Collection) { if !collection.is_empty() { collection.clear() } }
但如果修改Trait定义,改为为引用类型实现Trait、方法按值接收self(即引用本身),就会触发编译错误:
trait IsEmpty { fn is_empty(self) -> bool; } trait Clear { fn clear(self); } fn clear_non_empty<'a, Collection>(collection: &'a mut Collection) where &'a mut Collection: Clear, &'a Collection: IsEmpty, { if !collection.is_empty() { collection.clear() } }
对应的编译报错如下:
error[E0502]: cannot borrow `*collection` as mutable because it is also borrowed as immutable --> src/lib.rs:15:9 | 9 | fn clear_non_empty<'a, Collection>(collection: &'a mut Collection) | -- lifetime `'a` defined here ... 14 | if !collection.is_empty() { | --------------------- | | | immutable borrow occurs here | argument requires that `*collection` is borrowed for `'a` 15 | collection.clear() | ^^^^^^^^^^^^^^^^^^ mutable borrow occurs here For more information about this error, try `rustc --explain E0502`.
核心原因
核心差异来自Rust借用检查器对方法接收者生命周期的推断规则不同:
- 当Trait方法以
&self/&mut self为接收者时,方法调用产生的借用生命周期是编译器自动推断的临时借用:is_empty()调用时拿到的不可变引用,会在方法返回后立刻被释放,不会持续到后续clear()调用的位置,因此可变借用和不可变借用的活跃范围没有重叠,符合借用规则。 - 当你为
&'a Collection/&'a mut Collection这类引用类型实现Trait、方法按值接收self时,where约束里显式要求调用方法时传入的引用必须存活整个'a生命周期——这个'a是你在函数签名上定义的、覆盖整个函数执行周期的生命周期。也就是说is_empty()调用产生的不可变借用需要一直存活到函数返回,此时后续调用clear()申请可变借用时,不可变借用还处于活跃状态,二者作用域完全重叠,直接触发借用冲突。
内容的提问来源于stack exchange,提问作者Azat Ibrakov
相关产品推荐
相关产品推荐

