Mutability issue


#1
fn main() {
	let f1 = Feature {};
	let f2 = Feature {};
	let mut holder = Holder { features : vec![ f1, f2] };

	do_sth(&mut holder.features[0], &mut holder.features[1]);
}

struct Holder {
	features : Vec<Feature>
}

struct Feature {

}

fn do_sth(feature1 : &mut Feature, feature2 : &mut Feature) {

}

I know why compiler can not work, and know how to solve it in this simple codes, but my question is, if I can only get ‘holder’ not ‘f1’ or ‘f2’, in other words, I can only get Feature from ‘holder’, how to satisfy the function do_sth, assume the function do_sth is in other mod, and know nothing about ‘holder’ or ‘f1’ or ‘f2’, only function do_sth know is ‘Feature’.


#2

Probably need to use split_at_mut (https://doc.rust-lang.org/std/primitive.slice.html#method.split_at_mut). The issue is that Rust understands disjoint/split borrows of struct fields, but not of slices.


#3

If struct Holder has two fields: f1 : Feature and f2 : Feature, I also can only get Feature from ‘holder’ ,how to solve it?


#4
let mut holder = Holder {f1: f1, f2:f2};
do_sth(&mut holder.f1, &mut holder.f2);

#5

Ok, to forestall the obvious question this raises:

The compiler cannot “see” inside a Vec to know that v[0] and v[1] don’t overlap. It can see inside a struct to know that its fields don’t overlap. I believe that all built-in types (with the exception of arrays) are “transparent” to the compiler. If it’s defined in a library, you’re outta luck.

Edit: “But why can’t it see inside? It knows what it looks like!”

I was trying to go to bed, and… oh, fine. It’s because indexing involves using the Index and IndexMut traits, which execute arbitrary code, and the compiler doesn’t want to be in the business of trying to solve what random bits of code do.


#6

Oh, I see.
Back to the Vec version of Holder, you mention splite_at_mut, however, if the vec holds many elements, how to find the two mut ref element I want?


#7

That’s an exercise left for the reader :slight_smile:. The idea would be to find an index to split at such that each feature is in a different slice. Once you get the 2 separate mutable slices, you would treat them as any ordinary slice/vec where you need to get a reference out of. Maybe someone has a better idea.

This might also be a good time to pause and consider if there’s a better design/data model that doesn’t require this.


#8
fn double_index_mut<T>(s: &mut [T], i1: usize, i2: usize) -> (&mut T, &mut T) {
    let (i1, i2) = if i1 < i2 { (i1, i2) } else { (i2, i1) };
    let (low, high) = s.split_at_mut(i2);
    (&mut low[i1], &mut high[0])
}

#10

@vitalyd @DanielKeep @cuviper
Thank you for your helps.