此代码有效:
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 / ′
} 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 / ′
} 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 / ′
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `to_factor` occurs here
对我来说似乎没问题 - 当我们改变to_factor
时,借用应该“超过”,当然?
如果我用实际函数替换is_div
来增加混淆:
fn is_div(n: &BigInt, p: &BigInt) -> bool {
return to_factor % p == BigInt::zero()
}
它工作正常。
我是Rust的初学者,但不是一般的编程。我很确定这与所有权有关,但它也可能与闭包的实现方式有关?
这些示例是我尝试编写的实际代码中的MWE。它们在这一点上并没有真正意义,但它们表现出相同的编译错误。
答案 0 :(得分:4)
您正在遇到Rust类型系统的实现限制,特别是关于闭包参数的类型推断。也就是说,当你声明一个与立即使用的闭包相比没有立即使用的闭包时,推断的类型会略有不同。
此闭包有效,因为类型推断可以立即将参数连接到参数:
loop {
if (|n, p| n % p == zero)(&to_factor, &prime) {
to_factor = &to_factor / ′
} else {
break;
}
}
这也有效,因为我们立即定义了参数的类型:
let is_div = |n: &BigInt, p: &BigInt| n % p == zero;
loop {
if is_div(&to_factor, &prime) {
to_factor = &to_factor / ′
} else {
break;
}
}
这也是您的功能版本有效的原因。
问题跟踪器上有很多问题(搜索起来非常困难!),但12679是较旧的问题。
这是您经常看到内联定义的闭包的原因。
答案 1 :(得分: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 / ′
} else {
break;
}
}
println!("{}", to_factor);
}