This is valid D code:
struct Foo {
uint x;
uint[2] v;
void bar() {
x++;
}
void spam() {
foreach (_; v)
bar();
}
}
void main() {}
You can’t translate it to this Rust code:
struct Foo {
x: u32,
v: [u32; 2]
}
impl Foo {
fn new() -> Self {
Foo { x: 0, v: [0; 2] }
}
fn bar(&mut self) {
self.x += 1;
}
fn spam(&mut self) {
for _ in self.v.iter() {
self.bar();
}
}
}
fn main() {}
It gives an error:
error: cannot borrow `*self` as mutable because `self.v` is also borrowed as immutable [--explain E0502]
--> ...\test.rs:17:13
|>
16 |> for _ in self.v.iter() {
|> ------ immutable borrow occurs here
17 |> self.bar();
|> ^^^^ mutable borrow occurs here
18 |> }
|> - immutable borrow ends here
I solve the problem this way, using a “static” method, and passing to it as mutable reference arguments the unborrowed struct fields I need to use or modify:
struct Foo {
x: u32,
v: [u32; 2]
}
impl Foo {
fn new() -> Self {
Foo { x: 0, v: [0; 2] }
}
fn bar(x: &mut u32) {
*x += 1;
}
fn spam(&mut self) {
for _ in self.v.iter() {
Self::bar(&mut self.x);
}
}
}
fn main() {}
But is it a good idea to introduce some syntax to specify just a subset of the fields, allowing to use a more natural instance method?
struct Foo {
x: u32,
v: [u32; 2]
}
impl Foo {
fn new() -> Self {
Foo { x: 0, v: [0; 2] }
}
fn bar(&self(mut x)) {
self.x += 1;
}
fn spam(&mut self) {
for _ in self.v.iter() {
self.bar();
}
}
}
fn main() {}
That optional &self(mut x)
fantasy syntax is also useful for regular instance methods, when you want to better specify (and enforce) in the method signature what instance fields the method is allowed to use. This makes the flow of information between the struct methods more explicit and could avoid some mistakes. Static analysis tools will love that extra information.