代码之家  ›  专栏  ›  技术社区  ›  Bauxite

为什么借用会阻止在数组访问中内联函数调用?[副本]

  •  0
  • Bauxite  · 技术社区  · 8 年前

    我正在用Rust编写一些代码,用于生成46445645564584的Collatz序列中的前500个数字。

    use std::fmt::Debug;
    
    //Calculate the first 500 numbers in the Collatz sequence of 46445645645564584
    
    fn main() {
        let mut v = vec![46445645645564584];
    
        for _ in 0..500 {
            let last = v[v.len() - 1];
            v.push(next(last));
        }
    
        print_array(&v);
    }
    
    fn next(n: i64) -> i64 {
        if n % 2 == 0 {
            n / 2
        } else {
            3 * n + 1
        }
    }
    
    fn print_array<T: Debug>(v: &[T]) {
        for x in v {
            println!("{:?}", x);
        }
    }
    

    这是可行的,但我想内联变量 last :

    for _ in 0..500 {
        v.push(next(v[v.len() - 1]));
    }
    

    在我看来,这不应该改变程序的语义,因为我只是内联了一个变量。但是,当我尝试编译此文件时,Rust编译器会出现以下错误:

    error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
     --> src/main.rs:9:21
      |
    9 |         v.push(next(v[v.len() - 1]));
      |         -           ^              - mutable borrow ends here
      |         |           |
      |         |           immutable borrow occurs here
      |         mutable borrow occurs here
    
    error[E0502]: cannot borrow `v` as immutable because it is also borrowed as mutable
     --> src/main.rs:9:23
      |
    9 |         v.push(next(v[v.len() - 1]));
      |         -             ^            - mutable borrow ends here
      |         |             |
      |         |             immutable borrow occurs here
      |         mutable borrow occurs here
    

    在我看来 v 当值 v[v.len() - 1] 计算并传递给 next() . 这意味着 v 将在最外层调用中成功 v.push()

    我知道你也可以用迭代器/生成器来实现这一点,但我想知道为什么这会发生在这段特定的代码中,因为这可能是我在某个时候会再次遇到的问题。

    1 回复  |  直到 8 年前
        1
  •  0
  •   Izaak Weiss    8 年前

    虽然你是对的,原则上可以扩展Rust的borrow checker的功能,使其能够进行你所做的分析,但borrow checker目前还不能进行这种推理。

    v.push 借款 v ,然后,表达式 next(v[v.len() - 1]) 进行了分析;但是 v 已被借用 v、 推送 ,因此借用检查器失败。

    借用检查器可能很挑剔,显然它可以改进,但到目前为止,这是借用检查器的预期行为,解决方案是只将索引操作与推送操作分离,就像最初那样。编译器足够聪明,可以内联操作(在完成所有借用检查之后)。

    推荐文章