Rust能否静态实现self不同部分的差异化可变借用?
Rust prepare-commit模式结构体的字段级借用问题
我正在Rust中设计采用prepare-commit模式的结构体,简化后的代码如下:
struct Data { a: usize, } struct Adder<'a> { data: &'a mut Data, added: usize, } struct Holder<'a> { data: &'a Data, } impl<'a> Adder<'a> { fn add_once(&mut self) { // 仅需要可变访问added,不需要可变访问data self.added = self.added + self.data.a; } fn commit(&mut self) { // 仅需要可变访问data,不需要可变访问added self.data.a = self.added; } } fn main() { let mut d = Data { a: 1 }; let h = Holder { data: &d }; let mut ad = Adder { data: &mut d, added: 0, }; ad.add_once(); ad.add_once(); println!("{}", h.data.a); // 此处无法通过借用检查 ad.commit(); println!("{}", ad.data.a); }
这段代码无法通过编译。问题根源在于Adder实例创建时就对内部持有的data字段声明了可变借用,导致从实例创建开始,同作用域内其他所有对Data的不可变借用(比如示例中Holder持有的引用)都无法合法使用。但实际逻辑中add_once方法只需要可变访问自身的added字段,完全不需要对data做可变操作,只有最终调用commit写入结果时才需要可变访问data。理想状态下编译器应当能识别这种字段级的借用差异:add_once执行阶段不占用data的可变借用权限,允许Holder正常读取数据,只有调用commit时才触发可变借用的排他性检查。
目前已知两种可绕开编译错误的方案,但都存在明显缺陷:
- 将
Adder的字段用RefCell包裹,整体对Adder持不可变借用,需要修改字段时再动态获取可变借用。该方案的问题是RefCell的借用检查发生在运行时,而当前场景的借用规则完全可以在编译期校验,只是需要支持结构体不同字段独立应用借用规则,引入运行时检查属于不必要的开销。 - 用
unsafe块把引用转为裸指针自定义访问逻辑,但目前没有找到能部分保留借用检查的实现方式,不希望完全绕开编译器的借用校验:如果Holder的生命周期跨越了commit调用,编译器仍然需要能正常抛出借用错误。
核心问题
- Rust中是否存在静态、安全的语法支持,对
self的不同字段执行独立的、可变性不同的借用? - 如果不存在原生安全支持,有没有能满足需求、同时保留上述编译期借用检查能力的
unsafe实现样板?是否有现成的crate提供该能力? - 这类prepare-commit模式的场景,通用的最佳实践是什么?
- Rust语言层面有没有针对这类部分借用问题的相关RFC?
内容的提问来源于stack exchange,提问作者Chaser hkj
相关产品推荐
相关产品推荐

