Quickly get &mut [&mut T] from &mut [T]?

Is there a way to create a slice of mutable references to elements of another mutable slice (or vec or array) without iterating? Given that a slice is implemented as a pointer to another base vec or array plus a length field, it seems that the same implementation can be viewed as either having elements of the same type as the base vec or array, or as having elements that are references to the base vec's or array's elements. I am wondering if there is some way to get that second case without having to construct another vec/array with the references as elements as an intermediary.

No, unfortunately not. You can see this by just looking at the memory size of the underlying data:

  • x: &[T] has size sizeof::<T>() * x.len()
  • x: &[&T] has size sizeof::<&T>() * x.len()

Which are clearly not equal in the general case. Hence you need to have a new allocation.

2 Likes

In abstract, yes. In reality, no.

These two types have physically different and incompatible contents in memory, so when you have a &[T] (with more than one element), then &[&T] may not exist anywhere in memory. It's a brand new data layout that needs to be created and written to memory somewhere.

However, taking a reference effectively guarantees that there is no new allocation or copying happening, and that you merely access something that already exists. So by definition this operation can't exist [1]

What you can do is write a generic function for &[impl AsMut<T>], and the compiler will generate different versions of the function that read different memory layouts when given &mut [T] and &mut [&mut T]. You can also use a generic impl IntoIter<Item=&mut T>.


  1. apart from DerefMut abuse that horribly leaks memory, and even that is not implementable without a wrapper around [T] ↩︎

6 Likes

Just to be clear: What I meant to ask was if Rust has a way, given a &mut [T] or &mut Vec<T>, to quickly generate a slice structure of type &mut [&mut T]. I don't care whether the structs used to implement &mut [T] and &mut [&mut T] have the same actual size. All that I care about is to avoid building and populating a new vec as an intermediate value, as would be done by calling collect.

Although, now that I think about it more, I'm don't think this would help me at all. Because anything that could borrow one of the elements of the &mut [&mut T] slice would have to first borrow the whole slice, so there would be no advantage to this over using split_at_mut repeatedly on the original slice.

The size isn't the point, just a quick illustration of the problem. [T] and [&mut T] are entirely different things — one is a bunch of adjacent Ts, and one is a bunch of adjacent &mut Ts. There is no [&mut T] in memory, until you create one (such as by collecting into a Vec), and therefore there cannot be an &mut [&mut T], because an &mut [&mut T] must point to a [&mut T].

In order to avoid allocating memory for an [&mut T], you must avoid needing one. @kornel mentioned two ways to produce a similar effect — making the receiving code accept AsMut, or creating an iterator of &mut Ts. Both of these have the characteristic of creating the &mut Ts “just in time” as they are used, rather than requiring a whole slice of them.

6 Likes

Or just use each_mut.

2 Likes

I think I can use Cell::from_mut(myvec.as_mut_slice()).as_slice_of_cells() instead.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.