在 Rust 中访问 属性 后在 &mut self 上调用方法
Calling method on &mut self after accessing property in Rust
我需要从一个方法匹配 self
上的一个可选值,并根据该匹配调用 self
上可变地接受 self
的方法。我正在尝试做一个非常高性能的游戏,所以尽管我很想放弃可变性,但在这种情况下我做不到:这些方法确实需要可变地访问结构,而且它们确实需要根据结构属性进行分派。这是一个 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
我以为我已经与借用检查员和平相处,但显然不是:我不知道如何解决这个问题,虽然我知道为什么会这样。如果有人解释将来如何避免这种情况,我将不胜感激。
- 您可以在比赛中解开
Option(Baz)
而不是使用 if
let
..
- 将 foo 声明为可变的
这是代码...
enum Baz {
A,
B,
C,
}
struct Foo {
bar: Option<Baz>,
}
impl Foo {
pub fn dostuff(&mut self, fizz: i32) {
match self.bar {
Some(Baz::A) => self.do_a(fizz),
Some(Baz::B) => self.do_b(fizz + 2),
Some(Baz::C) => self.do_c(fizz + 1),
None => {},
}
}
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::B) };
foo.dostuff(3);
}
如果你关心引用,据我所知,Rust 的规则禁止你拥有这样的代码。您必须:
Copy
或 Clone
您的 bar
对象并根据需要展开。
添加一些标志并使代码不具有对该对象的多个引用。例如,添加两个变量,它们会告诉您要做什么。您匹配您的枚举,设置这些变量,然后匹配这些变量。这不如这里的第一项有用,但这也是一个解决方案。
更加实用-喜欢:
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);
}
通过这样做你 return 一个你想用它的参数调用的方法,所以你只需调用你需要的。我很确定这个解决方案可以在不使用 Box
的情况下重写,而只是引用一个方法,但我不知道如何。
我需要从一个方法匹配 self
上的一个可选值,并根据该匹配调用 self
上可变地接受 self
的方法。我正在尝试做一个非常高性能的游戏,所以尽管我很想放弃可变性,但在这种情况下我做不到:这些方法确实需要可变地访问结构,而且它们确实需要根据结构属性进行分派。这是一个 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
我以为我已经与借用检查员和平相处,但显然不是:我不知道如何解决这个问题,虽然我知道为什么会这样。如果有人解释将来如何避免这种情况,我将不胜感激。
- 您可以在比赛中解开
Option(Baz)
而不是使用if let
.. - 将 foo 声明为可变的
这是代码...
enum Baz {
A,
B,
C,
}
struct Foo {
bar: Option<Baz>,
}
impl Foo {
pub fn dostuff(&mut self, fizz: i32) {
match self.bar {
Some(Baz::A) => self.do_a(fizz),
Some(Baz::B) => self.do_b(fizz + 2),
Some(Baz::C) => self.do_c(fizz + 1),
None => {},
}
}
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::B) };
foo.dostuff(3);
}
如果你关心引用,据我所知,Rust 的规则禁止你拥有这样的代码。您必须:
Copy
或Clone
您的bar
对象并根据需要展开。添加一些标志并使代码不具有对该对象的多个引用。例如,添加两个变量,它们会告诉您要做什么。您匹配您的枚举,设置这些变量,然后匹配这些变量。这不如这里的第一项有用,但这也是一个解决方案。
更加实用-喜欢:
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); }
通过这样做你 return 一个你想用它的参数调用的方法,所以你只需调用你需要的。我很确定这个解决方案可以在不使用
Box
的情况下重写,而只是引用一个方法,但我不知道如何。