rust - 在 Rust 中访问属性后调用 &mut self 上的方法

标签 rust traits borrow-checker

我需要从一个方法匹配 self 上的可选值,并根据该匹配调用 self 上的方法,该方法采用 self 可变。我正在尝试做一个非常高性能的游戏,所以尽管我很想放弃可变性,但在这种情况下我做不到:这些方法确实需要可变地访问结构,而且它们确实需要根据结构属性进行分派(dispatch)。这是一个 MVCE:

enum Baz {
    A,
    B,
    C,
}
struct Foo {
    bar: Option<Baz>,
}

impl Foo {
    pub fn dostuff(&mut self, fizz: i32) {
        if let Some(ref b) = self.bar {
            match b {
                &Baz::A => self.do_a(fizz),
                &Baz::B => self.do_b(fizz + 2),
                &Baz::C => self.do_c(fizz + 1),
            }
        }
    }

    pub fn do_a(&mut self, f: i32) {
        println!("A, with fizz {}", f);
    }
    pub fn do_b(&mut self, f: i32) {
        println!("B, with fizz {}", f);
    }
    pub fn do_c(&mut self, f: i32) {
        println!("C, with fizz {}", f);
    }
}

fn main() {
    let foo = Foo { bar: Some(Baz::A) };
    foo.dostuff(3);
}

这里是 the playground .

error[E0502]: cannot borrow `*self` as mutable because `self.bar.0` is also borrowed as immutable
  --> src/main.rs:14:28
   |
12 |         if let Some(ref b) = self.bar {
   |                     ----- immutable borrow occurs here
13 |             match b {
14 |                 &Baz::A => self.do_a(fizz),
   |                            ^^^^ mutable borrow occurs here
...
18 |         }
   |         - immutable borrow ends here

我以为我已经与借用检查器和平相处,但显然不是:我不知道如何解决这个问题,尽管我知道为什么会这样。如果有人解释了将来如何避免这种情况,我将不胜感激。

最佳答案

如果您关心引用,据我所知,Rust 的规则禁止您使用此类代码。您必须:

  1. CopyClone 您的 bar 对象并根据需要展开。
  2. 添加一些标志并使代码不具有对该对象的多个引用。例如,添加两个变量,它们会告诉您要做什么。您匹配您的枚举,设置这些变量,然后匹配这些变量。这不如这里的第一项有用,但这也是一个解决方案。

  3. 更像功能性:

    enum Baz {
        A,
        B,
        C,
    }
    struct Foo {
        bar: Option<Baz>,
    }
    
    impl Foo {
        pub fn dostuff(&mut self, fizz: i32) {
            let (method, arg) = match self.bar {
                Some(ref b) => {
                    match b {
                        &Baz::A => (Self::do_a as fn(&mut Self, i32)>, fizz),
                        &Baz::B => (Self::do_b as fn(&mut Self, i32)>, fizz + 2),
                        &Baz::C => (Self::do_c as fn(&mut Self, i32)>, fizz + 1),
                    }
                },
                None => return,
            };
            method(self, arg);
        }
    
        pub fn do_a(&mut self, f: i32) {
            println!("A, with fizz {}", f);
        }
        pub fn do_b(&mut self, f: i32) {
            println!("B, with fizz {}", f);
        }
        pub fn do_c(&mut self, f: i32) {
            println!("C, with fizz {}", f);
        }
    }
    
    fn main() {
        let mut foo = Foo { bar: Some(Baz::A) };
        foo.dostuff(3);
    }
    

    这样你就返回了一个你想用它的参数调用的方法,所以你只需调用你需要的。我很确定这个解决方案可以在不使用 Box 的情况下重写,只是引用一个方法,但我不知道如何。

关于rust - 在 Rust 中访问属性后调用 &mut self 上的方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45581398/

相关文章:

rust - 如何从文件向量创建单个流?

regex - 如何在 Rust 中获取重叠的正则表达式捕获?

vector - 检查 Vec 是否包含来自另一个 Vec 的所有元素

java - Scala 选择在签名冲突的情况下实现哪个特征?

scala - 将特征限制为对象?

rust - 由于需求冲突,无法推断出自动强制的适当生命周期

tree - 我如何反序列化 Rust 中的引用树?

rust - 有没有一种方法可以将SDL2字体呈现为等距?

generics - 如何将值映射到 Rust 中的类型?

rust - 如何告诉 Rust 编译器借用已经结束?