Can I convert &mut [&mut T] into &mut [T]?

#[derive(Default, Clone)]
struct Ends {
    n: i32,
}

trait EndExt {
    fn set_n(&mut self, n:i32);
    
    fn get_n(&self) -> i32;
}

impl EndExt for Ends {
    fn set_n(&mut self, n:i32) {
        self.n = n;
    }

    fn get_n(&self) -> i32 {
        self.n
    }
}

fn do_something<T: EndExt>(a: &mut [T], b:&T) {
    let mut sub_a = Vec::new();
    
    for e in a.iter_mut() {
        if e.get_n() % 2 == 0 {
            sub_a.push(e);
        }
        
    }

    worker_in_deeper(sub_a.as_mut_slice(), b);
}

fn worker_in_deeper<T: EndExt>(a: &mut [T], b:&T) {
  // do something
}

fn main() {
    let mut ends_vec = vec![Ends::default(); 100];

    do_something(ends_vec.as_mut_slice(), &Ends{n:256});
}

The above codes won't compile:

error[E0277]: the trait bound `&mut T: EndExt` is not satisfied
  --> src/tests/help_me.rs:39:5
   |
39 |     worker_in_deeper(sub_a.as_mut_slice(), b);
   |     ^^^^^^^^^^^^^^^^ the trait `EndExt` is not implemented for `&mut T`
   |
   = help: the trait `EndExt` is implemented for `Ends`
note: required by a bound in `worker_in_deeper`
  --> src/tests/help_me.rs:42:24
   |
42 | fn worker_in_deeper<T: EndExt>(a: &mut [T], b:&T) {
   |                        ^^^^^^ required by this bound in `worker_in_deeper`


In the above situation, can I convert &mut [&mut T] into &mut [T]?

Or any solutions to solve this?

The answer to the question is no, but it would make more sense for worker_in_deeper to take an iterator:

fn do_something<T: EndExt>(a: &mut [T], b: &T) {
    let sub_a = a.iter_mut().filter(|e| e.get_n() % 2 == 0);

    worker_in_deeper(sub_a, b);
}

fn worker_in_deeper<'a, T, I>(_a: I, _b: &T)
where
    T: EndExt + 'a,
    I: IntoIterator<Item = &'a mut T>,
{
    // do something
}

You might also want to make do_something take an iterator.

2 Likes

To elaborate on @drewtato's answer, the reason you can't turn a &mut [&mut T] into a &mut [T] is because a &mut [T] is a reference to a single slice of contiguous T's, whereas a &mut [&mut T] is a bunch of references to slices of T's, where each of those slices could be placed anywhere in memory.

If you really wanted everything to be in a single slice, you would need to copy all the T's into something like a Vec<T> so the elements are guaranteed to be next to each other.

However, you can turn something like a &mut [&mut T] into an iterator quite easily if all you need is to access each element in turn.

2 Likes

Is converting &[&T] into &[T] impossible also?

Yes, for exactly the same reason. If you want to move things around in memory so they are contiguous, you'll need to make a temporary copy or new allocation (depending on where the original &[&T] came from).

There are some unsafe tricks that you might be able to use in the really niche case that the values being referred to are already contiguous (e.g. because they came from slice::chunks()), but it's quite nuanced (the term is "pointer provenance") and will probably be UB unless you really know what you are doing.

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.