参数可以传递给函数并修改:
fn set_42(int: &mut i32) { *int += 42; } fn main() { let mut int = 0; set_42(&mut int); println!("{:?}", int); }
输出:
42
天真地改变代码以使用切片失败了一大堆错误:
fn pop_front(slice: &mut [i32]) { *slice = &{slice}[1..]; } fn main() { let mut slice = &[0, 1, 2, 3][..]; pop_front(&mut slice); println!("{:?}", slice); }
输出:
:2:14: 2:27 error: mismatched types: expected `[i32]`, found `&[i32]` (expected slice, found &-ptr) [E0308] :2 *slice = &{slice}[1..]; ^~~~~~~~~~~~~ :2:14: 2:27 help: see the detailed explanation for E0308 :2:5: 2:11 error: the trait `core::marker::Sized` is not implemented for the type `[i32]` [E0277] :2 *slice = &{slice}[1..]; ^~~~~~ :2:5: 2:11 help: see the detailed explanation for E0277 :2:5: 2:11 note: `[i32]` does not have a constant size known at compile-time :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
如果我们尝试使用一个可变切片(这不是我真正想要的;我不想修改切片中的值,我只想修改切片本身,以便它覆盖更小范围的元素)和一个可变的参数,它对原始切片没有影响:
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); }
输出:
[0, 1, 2, 3]
问题:有没有办法修改作为函数参数的切片?我不想修改切片中的元素; 我只想修改切片本身的范围,使其成为一个较小的"子切片".
正如其他人说,这里的核心思想是采取&mut &... [T]
(其中...
为mut
或空)和读/写内部切片.其他答案表明它可以&mut &[T]
在安全的代码中使用,并且可能存在&mut &mut [T]
不安全的代码,但它们无法解释为什么存在差异......并且&mut &mut [T]
也可以使用安全代码.
在显式生命周期术语中,嵌套引用类似于&'a mut &'b ... [T]
某些生命周期'a
和' b
,并且这里的目标是获取a &'b ... [T]
,切片并将其写入&'a mut
.
因为&'a mut &'b [T]
,这很简单:&[T]
是复制,因此写入*slice = &slice[1..]
将有效地复制&'b [T]
出来,&mut
然后,稍后用较短的一个覆盖现有值.复制意味着一个字面上得到一个&'b [T]
操作&'a mut
,因此它和它之间没有直接连接,因此变异是合法的.它实际上是类似的东西
fn pop_front<'a, 'b>(slice: &'a mut &'b[i32]) { // *slice = &slice[1..] behaves like let value: &'b [i32] = *slice; *slice = &value[1..] }
(我已经标记了生命周期并注释了与我的解释相关的类型,但这不是代码工作所必需的.)
因为&'a mut &'b mut [T]
事情有点棘手:&mut [T]
无法复制:解除引用不会复制,它会重新给予一个&'a mut [T]
即切片有一个连接到外部 &'a mut
而不是内部的生命周期&'b mut [T]
.这意味着切片引用的生命周期比它尝试覆盖的类型更短,因此将切片存储到该位置是无效的.换一种说法:
fn pop_front<'a, 'b>(slice: &'a mut &'b mut [i32]) { let value: &'a mut [i32] = &mut **slice; *slice = &mut value[1..] // error }
安全地执行此操作的方法&'a mut &'b mut [T]
是使用该'b
生命周期从内部切片中取出内部切片.这需要跟踪"一个所有者"规则,不进行借用,并且这种所有权操纵的最佳功能是mem::replace
.它允许我们&'b mut [T]
通过用一些占位符交换它来提取内部,然后我们可以用短版本覆盖它.最好/唯一的占位符是一个空数组:写入&mut []
可以是&'c mut [X]
任何类型X
和任何生命周期'c
,因为没有数据要存储,因此不需要初始化,也没有数据会变得无效.特别是,它可以是&'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..] }
(如上所述,我做的事情比必要的更明确.)