为什么通过特征对象进行突变会失败,但通过函数指针进行突变却可以?

问题描述 投票:0回答:1

我有一个 Rust 程序,其中包含两个版本的结构及其方法实现。第一个版本使用函数指针,而第二个版本使用装箱特征对象。这是代码:

pub struct FnWrapper1 {
    pub f: fn(&mut BoolAndFns1),
}

pub struct BoolAndFns1 {
    pub b: bool,
    pub fs: Vec<FnWrapper1>,
}

impl BoolAndFns1 {
    pub fn meth(&mut self) {
        if let Some(wrapper) = self.fs.last_mut() {
            (wrapper.f)(self);
        }
    }
}

pub struct FnWrapper2 {
    pub f: Box<dyn Fn(&mut BoolAndFns2)>,
}

struct BoolAndFns2 {
    pub b: bool,
    pub fs: Vec<FnWrapper2>,
}

impl BoolAndFns2 {
    pub fn meth(&mut self) {
        if let Some(wrapper) = self.fs.last_mut() {
            (wrapper.f)(self);
        }
    }
}

fn main() {
    let mut bf1 = BoolAndFns1 {
        b: false,
        fs: vec![FnWrapper1 {
            f: |bf| {
                bf.b = true;
            },
        }],
    };
    bf1.meth();

    let mut bf2 = BoolAndFns2 {
        b: false,
        fs: vec![FnWrapper2 {
            f: Box::new(|bf2| {
                bf2.b = true;
            }),
        }],
    };
    bf2.meth();
}

当我尝试编译此程序时,Rust 编译器给出错误:

FnWrapper2
:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:30:16
   |
29 |         if let Some(wrapper) = self.fs.last_mut() {
   |                                ------- first mutable borrow occurs here
30 |             (wrapper.f)(self);
   |             ----------- ^^^^ second mutable borrow occurs here
   |             |
   |             first borrow later used by call

但是

FnWrapper1
没有错误。

因此,我有两个问题:

  1. 为什么在将可变引用传递到函数指针时,第二次改变变量是有效的,但在将其传递到装箱特征对象时却无效?
  2. 第二个版本可以用吗?
rust compiler-errors borrow-checker mutation
1个回答
2
投票

区别在于,函数指针确实实现了

Copy
,因此
wrapper.f
不是借用 self
。您可以通过暂时从向量中删除该函数而不是引用它来避免别名:

impl BoolAndFns2 { pub fn meth(&mut self) { if let Some(wrapper) = self.fs.pop() { (wrapper.f)(self); self.fs.push(wrapper); } } }
    
© www.soinside.com 2019 - 2024. All rights reserved.