2016-12-16 25 views
12

这里发生了什么(playground)?不能借用不可变因为它也借用函数参数中的可变

struct Number { 
    num: i32 
} 

impl Number { 
    fn set(&mut self, new_num: i32) { 
     self.num = new_num; 
    } 
    fn get(&self) -> i32 { 
     self.num 
    } 
} 

fn main() { 
    let mut n = Number{ num: 0 }; 
    n.set(n.get() + 1); 
} 

给出了这样的错误:

error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable 
    --> <anon>:17:11 
    | 
17 |  n.set(n.get() + 1); 
    |  - ^  - mutable borrow ends here 
    |  |  | 
    |  |  immutable borrow occurs here 
    |  mutable borrow occurs here 

但是如果你只是简单的代码更改为这它的工作原理:

fn main() { 
    let mut n = Number{ num: 0 }; 
    let tmp = n.get() + 1; 
    n.set(tmp); 
} 

对我来说,那些看起来完全等同 - 我的意思是,我希望前者在编译过程中转换为后者。在评估下一级函数调用之前,Rust是否评估所有函数参数?

+0

你可以在这里找到借用检查过程的细节(https://github.com/rust-lang/rust/tree/master/src/librustc_borrowck/borrowck)。 – ljedrz

+1

解决方法有[unborrow macro](https://github.com/durka/unborrow),以及关于[reddit]的讨论(https://www.reddit.com/r/rust/comments/575tc7/why_does_rust_not_allow_disjoint_mutable_borrows /) – wimh

+0

啊哈,谢谢wimh! – Timmmm

回答

11

这条线:

n.set(n.get() + 1); 

被脱到

Number::set(&mut n, n.get() + 1); 

错误消息可能是有点更清晰现在:

error[E0502]: cannot borrow `n` as immutable because it is also borrowed as mutable 
    --> <anon>:18:25 
    | 
18 |  Number::set(&mut n, n.get() + 1); 
    |      -^  - mutable borrow ends here 
    |      | | 
    |      | immutable borrow occurs here 
    |      mutable borrow occurs here 

锈评估左到右的论点,该代码等同于:

let arg1 = &mut n; 
let arg2 = n.get() + 1; 
Number::set(arg1, arg2); 

现在应该很明显什么是错的。交换前两行,修复了这一点,但Rust并没有进行这种控制流分析。

这是第一个创建为bug #6268,现在它被集成到RFC 811

自2018-01-13每晚1.25.0起,为possible to use non-lexical lifetimes。如果你每晚在Rust上运行你的例子并且使用#![feature(nll)]来启用NLL功能门,那么它就是will now compile without an error

相关问题