【问题标题】:Mutating an upvar captured by value in a FnMut closure在 FnMut 闭包中改变由值捕获的 upvar
【发布时间】:2015-05-05 13:03:28
【问题描述】:

我正在尝试创建一个简单的程序,其中包含一个逐渐清空自身的集合的闭包:

fn main() {
    let vector = vec![1, 2, 3];

    let mut allow_once = move |i: &i32| -> bool {
        if let Some(index) = vector.position_elem(i) {
            vector.remove(index);
            return true
        }
        false
    };

    for e in &[1, 2, 3, 1, 2, 3] {
        let is_in = if allow_once(e) { "is" } else { "is not" };
        println!("{} {} allowed", e, is_in);
    }
}

这似乎是犹太洁食(对我而言),但 rustc 抱怨(每晚):

<anon>:6:13: 6:19 error: cannot borrow captured outer variable in an `FnMut` closure as mutable
<anon>:6             vector.remove(index);
                     ^~~~~~

我预计问题可能是脱糖问题之一。也就是说,虽然实现从不违反 Aliasing XOR Mutation 原则,但可能是去保证让rustc 没有意识到这一点。

因此:

  1. 这是暂时的限制/错误还是固有的?
  2. 如何尽可能高效地创建具有可变环境的闭包?

注意:通过引用捕获不是一个选项,我希望能够移动闭包。

【问题讨论】:

  • 约定是 vec![1, 2, 3] 优于 vec!(1, 2, 3),顺便说一句。
  • @ChrisMorgan:已编辑 :)

标签: closures rust


【解决方案1】:

事实上,这个问题很容易解决。只需将mut 限定符添加到vector

fn main() {
    let mut vector = vec![1, 2, 3];

    let mut allow_once = move |i: &i32| -> bool {
        if let Some(index) = vector.position_elem(i) {
            vector.remove(index);
            true
        } else { false }
    };

    for e in &[1, 2, 3, 1, 2, 3] {
        let is_in = if allow_once(e) { "is" } else { "is not" };
        println!("{} {} allowed", e, is_in);
    }
}

(工作代码here

这只是与往常一样的可变性规则 - 为了改变某些东西,它必须在某个地方有 mut,无论是在其变量声明中还是在其类型 (&amp;mut) 中。

【讨论】:

  • 噢!我认为声明 allow_once mut 就足够了(继承的可变性)并尝试了所有不足之处......
  • 是的,一方面它可能看起来令人困惑,但另一方面变量之间没有明确的移动,所以mut 规则仍然有效。例如,如果这是一个 FnOnce 闭包,您可以像 let mut vector = vector 这样移动变量,然后在原始变量上使用 mut 限定符。
  • 我想在main()的末尾打印向量的长度,如果我添加println!("{}", vector.len());,编译器实际上会说,cannot move out of `vector` because it is borrowed rustc(E0505)
猜你喜欢
  • 2019-04-01
  • 1970-01-01
  • 2020-10-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多