首页 文章

当内联的相同代码没有时,为什么闭包会引入借位?

提问于
浏览
2

此代码有效:

extern crate num;

use num::{BigInt, FromPrimitive, Zero};

fn sample() {
    let mut to_factor = "600851475143".parse::<BigInt>().unwrap();

    let mut prime = BigInt::from_i32(2).unwrap();

    let zero = BigInt::zero();

    //let is_div = |n, p| { n % p == zero};

    loop {
        if &to_factor % &prime == zero {
            to_factor = &to_factor / &prime;
        } else {
            break;
        }
    }

    println!("{}", to_factor);
}

但是如果我尝试用闭包替换循环中的条件,它就不再编译了:

fn sample() {
    let mut to_factor = "600851475143".parse::<BigInt>().unwrap();

    let mut prime = BigInt::from_i32(2).unwrap();

    let zero = BigInt::zero();

    let is_div = |n, p| { n % p == zero};

    loop {
        if is_div(&to_factor, &prime) {
            to_factor = &to_factor / &prime;
        } else {
            break;
        }
    }

    println!("{}", to_factor);
}

错误如下:

error[E0506]: cannot assign to `to_factor` because it is borrowed
  --> src/main.rs:16:13
   |
15 |         if is_div(&to_factor, &prime) {
   |                    --------- borrow of `to_factor` occurs here
16 |             to_factor = &to_factor / &prime;
   |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `to_factor` occurs here

对我来说似乎很好 - 当我们改变 to_factor 时,借用应该是"over",当然?

为了增加混淆,如果我用实际函数替换 is_div

fn is_div(n: &BigInt, p: &BigInt) -> bool {
    return to_factor % p == BigInt::zero()
}

它工作正常 .

我是Rust的初学者,但不是一般的编程 . 我很确定这与所有权有关,但它也可能与如何实现闭包有关?

这些示例是我尝试编写的实际代码中的MWE . 它们在这一点上并没有真正意义,但它们表现出相同的编译错误 .

2 回答

  • 4

    您正在遇到Rust类型系统的实现限制,特别是关于闭包参数的类型推断 . 也就是说,当你声明一个与立即使用的闭包相比没有立即使用的闭包时,推断的类型会略有不同 .

    这种闭包有效,因为类型推断可以立即将参数连接到参数:

    loop {
        if (|n, p| n % p == zero)(&to_factor, &prime) {
            to_factor = &to_factor / &prime;
        } else {
            break;
        }
    }
    

    这也有效,因为我们立即定义参数的类型:

    let is_div = |n: &BigInt, p: &BigInt| n % p == zero;
    
    loop {
        if is_div(&to_factor, &prime) {
            to_factor = &to_factor / &prime;
        } else {
            break;
        }
    }
    

    这也是您的功能版本工作的原因 .

    在问题跟踪器上有很多问题(这是一个非常难以搜索的东西!),但是12679是一个较旧的问题 .

    这是您经常看到内联定义的闭包的原因 .

  • 0

    正如你所写的那样, is_div 闭包不会借用 to_factor ,它会永远占用它 . 如果您将闭包签名更改为借用 to_factor 则可行 .

    let is_div = |&n, p| { n % p == zero};
    

    不能在操场上使用板条箱,但这说明了这一点 .

    fn main() {
        let mut to_factor = "654684234".parse::<i32>().unwrap();
    
        let prime = 2;
    
        let zero = 0;
    
        let is_div = |&n, p| n % p == zero;
    
        loop {
            if is_div(&to_factor, &prime) {
                to_factor = &to_factor / &prime;
            } else {
                break;
            }
        }
    
        println!("{}", to_factor);
    }
    

相关问题