You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The single "fight-compiler" exercise borrows the list for iteration, then attempts to borrow the structure mutably in each iteration, which naturally fails.
One of the reasons why this fails is that do_something receives a reference to the entire structure, meaning that it could (in principle) mutate the list while the iteration is ongoing in run. Obviously, Rust forbids this.
However, the proposed solution (https://github.com/sunface/rust-by-practice/blob/master/solutions/fight-compiler/borrowing.md) involves refactoring the iteration to a regular indexed loop. This doesn't actually solve the underlying (potential) safety hazard: do_something could still mutate the list, which could cause the caller to panic unexpectedly if e.g. the list was truncated by some other implementation of do_something. It can be argued that the API is broken here, because it does not appropriately restrict implementers from doing unexpected things.
There are a few ways this can be solved (IMHO) more cleanly, although they involve changing the API of do_something:
Don't give do_something access to &mut self; instead, give it a &mut i32 reference so it is only capable of mutating a and not list. So, pub fn do_something(a: &mut i32, n: i32) { *a = n; }
Convert do_something to a closure. Closures get special treatment because the compiler can directly see what they borrow. So, for example, self.list.iter().for_each(|i| { self.a = *i; }); works. In fact, we can even do something like self.list.iter().for_each(|i| { self.a = self.list[(7 - *i) as usize]; });, borrowing list immutably and a mutably, which (AFAIK) you simply cannot do with a separate function.
The text was updated successfully, but these errors were encountered:
The single "fight-compiler" exercise borrows the list for iteration, then attempts to borrow the structure mutably in each iteration, which naturally fails.
One of the reasons why this fails is that
do_something
receives a reference to the entire structure, meaning that it could (in principle) mutate the list while the iteration is ongoing inrun
. Obviously, Rust forbids this.However, the proposed solution (https://github.com/sunface/rust-by-practice/blob/master/solutions/fight-compiler/borrowing.md) involves refactoring the iteration to a regular indexed loop. This doesn't actually solve the underlying (potential) safety hazard:
do_something
could still mutate the list, which could cause the caller to panic unexpectedly if e.g. the list was truncated by some other implementation ofdo_something
. It can be argued that the API is broken here, because it does not appropriately restrict implementers from doing unexpected things.There are a few ways this can be solved (IMHO) more cleanly, although they involve changing the API of
do_something
:do_something
access to&mut self
; instead, give it a&mut i32
reference so it is only capable of mutatinga
and notlist
. So,pub fn do_something(a: &mut i32, n: i32) { *a = n; }
do_something
to a closure. Closures get special treatment because the compiler can directly see what they borrow. So, for example,self.list.iter().for_each(|i| { self.a = *i; });
works. In fact, we can even do something likeself.list.iter().for_each(|i| { self.a = self.list[(7 - *i) as usize]; });
, borrowinglist
immutably anda
mutably, which (AFAIK) you simply cannot do with a separate function.The text was updated successfully, but these errors were encountered: