How can I change the slice, which is a function parameter?

Parameters can be passed to functions and changed:

fn set_42(int: &mut i32) { *int += 42; } fn main() { let mut int = 0; set_42(&mut int); println!("{:?}", int); } 

Output :

 42 

A naive code change to use a slice fails with a number of errors:

 fn pop_front(slice: &mut [i32]) { *slice = &{slice}[1..]; } fn main() { let mut slice = &[0, 1, 2, 3][..]; pop_front(&mut slice); println!("{:?}", slice); } 

Result :

 <anon>:2:14: 2:27 error: mismatched types: expected `[i32]`, found `&[i32]` (expected slice, found &-ptr) [E0308] <anon>:2 *slice = &{slice}[1..]; ^~~~~~~~~~~~~ <anon>:2:14: 2:27 help: see the detailed explanation for E0308 <anon>:2:5: 2:11 error: the trait `core::marker::Sized` is not implemented for the type `[i32]` [E0277] <anon>:2 *slice = &{slice}[1..]; ^~~~~~ <anon>:2:5: 2:11 help: see the detailed explanation for E0277 <anon>:2:5: 2:11 note: `[i32]` does not have a constant size known at compile-time <anon>:2:5: 2:11 note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors 

If we try to use a mutable slice (which I don’t want, I don’t want to change the values ​​inside the slice, I just want to change the slice itself so that it covers a smaller range of elements) and the mutable parameter, it does not affect the original slice:

 fn pop_front(mut slice: &mut [i32]) { slice = &mut {slice}[1..]; } fn main() { let mut slice = &mut [0, 1, 2, 3][..]; pop_front(&mut slice); println!("{:?}", slice); } 

Result :

 [0, 1, 2, 3] 

Question: Is there a way to change the slice, which is the parameter of the function? I do not want to change the elements inside the slice; I just want to change the range of the slice itself so that it becomes a smaller “sub-slice”.

+5
source share
3 answers

As others have said, the main idea here is to take &mut &... [T] (where ... is mut or empty) and read / write to the inner slice. Other answers demonstrate that it’s possible &mut &[T] in safe code and maybe &mut &mut [T] with unsafe code, but they do not explain why there is a difference ... and &mut &mut [T] with safe code too.

In expressions with explicit lifetimes, the nested link is something like &'a mut &'b ... [T] for some lifetimes of 'a and' b , and the goal here is to get a &'b ... [T] , slice and record this in &'a mut .

For &'a mut &'b [T] this is easy: &[T] is a copy, so writing *slice = &slice[1..] will effectively copy &'b [T] from &mut , and then overwrite the existing value more short. A copy means that it literally gets &'b [T] for work, and therefore there is no direct connection between this and &'a mut , and therefore it is legal to mutate. This is really something like

 fn pop_front<'a, 'b>(slice: &'a mut &'b[i32]) { // *slice = &slice[1..] behaves like let value: &'b [i32] = *slice; *slice = &value[1..] } 

(I have outlined lifetimes and annotated the type to associate it with my explanation, but this is not necessary for the code to work.)

For &'a mut &'b mut [T] everything is a little more complicated: &mut [T] cannot be copied: dereferencing will not be copied, it will reborrow to give &'a mut [T] , that is, the slice has a lifetime which is related to the external &'a mut , and not the internal &'b mut [T] . This means that the chopped link has a shorter lifetime than the type that it is trying to overwrite, so it is not valid for storing the fragment at this position. In other words:

 fn pop_front<'a, 'b>(slice: &'a mut &'b mut [i32]) { let value: &'a mut [i32] = &mut **slice; *slice = &mut value[1..] // error } 

A safe way for &'a mut &'b mut [T] is to get an internal slice from a link with this 'b lifetime. This requires tracking the “single owner” rule, without borrowing, and the best function for manipulating ownership is mem::replace . This allows us to extract the internal &'b mut [T] , replacing it with some kind of placeholder, which we can then overwrite with the short version. The best / only placeholder is an empty array: the entry &mut [] can be &'c mut [X] for any type X and any lifetime 'c , since there is no data to store, and therefore nothing needs to be initialized, and no data will never become invalid. In particular, it could be &'b mut [T] :

 fn pop_front<'a, 'b>(slice: &'a mut &'b mut [i32]) { let value: &'b mut [i32] = mem::replace(slice, &mut []); *slice = &mut value[1..] } 

(As above, I made things more explicit than necessary.)

+5
source

If you need to change an immutable snippet, see Cornstalks answer .

You cannot modify a mutable fragment in safe Rust. When you pick up a modified fragment, you actually borrow from the original fragment. This means that the object must not survive the original slice.

You need something similar to this:

 fn pop_front(slice: &mut &mut [i32]) { *slice = &mut slice[1..]; } 

but the subclass slice[1..] is valid only until the end of the function and which indicates that the borrowing will end and the original slice (parameter slice ) will be used again.

We can use some unsafe code to manually create the necessary slice:

 use std::slice; fn pop_front(slice: &mut &mut [i32]) { let ptr = slice.as_mut_ptr(); let len = slice.len(); *slice = unsafe { slice::from_raw_parts_mut(ptr.offset(1), len - 1) }; } fn main() { let mut slice = &mut [0, 1, 2, 3][..]; pop_front(&mut slice); println!("{:?}", slice); } 

playground

This program displays:

 [1, 2, 3] 
+3
source

Using the Answer part by Francis Gagné (I was not thinking about trying &mut & ), I managed to get it to work without using unsafe code:

 fn pop_front(mut slice: &mut &[i32]) { *slice = &slice[1..]; } fn main() { let mut slice = &[0, 1, 2, 3][..]; pop_front(&mut slice); println!("{:?}", slice); } 

Output :

 [1, 2, 3] 
+3
source

Source: https://habr.com/ru/post/1238782/


All Articles