In the code below (playground), the borrow checker refutes the default implementation of conditional_insert because the iterator obtained from self.get_iterator() also borrows self, which prevents subsequent modification of self via self.set_flag(..).
My intend is to decouple the struct Data from its use by means of "getters" in the default trait method implementation but apparently I do something wrong and/or this is not the rust way to do it.
I suppose that I could clone self before calling get_iterator() but this seems not very efficient.
struct Data {
vec: Vec<u32>,
flag: u32,
}
trait Getters {
fn get_iterator(&self) -> impl Iterator<Item=&u32> + '_;
fn set_flag(&mut self, val: u32);
}
trait Operation : Getters {
fn operation(&mut self){
for val in self.get_iterator() {
self.set_flag(*val);
}
}
}
impl Getters for Data {
fn get_iterator(&self) -> impl Iterator<Item=&u32> + '_ {
self.vec.iter()
}
fn set_flag(&mut self, val: u32) {
self.flag = val;
}
}
impl Operation for Data {}
fn main() {
let mut data = Data {vec : vec![1,2,3], flag: 4};
data.operation();
}
ps: I think my problem is similar to the problem discussed in this blog post but traits are not part of solution discussed there..
The fundamental problem here is that set_flag takes &mut self, which requires exclusive access to all of Data. There are a few different ways to get around this, and which one is best will depend on what your actual use case is:
Use the iterator to calculate the change that should be made, and then apply that change after iteration is finished. (Playground)
Provide a method that returns both the iterator and the mutable flag reference at the same time. (Playground)
Wrap flag in an interior mutability primitive, so that set_flag can take &self instead. (Playground)
Getters and setters in Rust are more limited than in other languages for the reasons you're experiencing here— Methods can't be any more fine-grained in their access control than the entire object, but you can borrow different fields independently if you're working with the structure directly. For this reason, Rust code generally prefers making fields public over writing getters and setters unless there's some extra verification that needs to be made.
In addition to what @2e71828 said, even if you use getters/setters to decouple Data from the POV of a consumer of your crate, it's more idiomatic in Rust to not use them within your crate (due to issues such as the one in this topic).