Rust 如何修改作为函数参数的切片?

Rust 如何修改作为函数参数的切片?,rust,Rust,可以将参数传递给函数并进行修改: fn set_42(int: &mut i32) { *int += 42; } fn main() { let mut int = 0; set_42(&mut int); println!("{:?}", int); } : 更改代码以使用切片失败,并出现一系列错误: fn pop_front(slice: &mut [i32]) { *slice = &{sl

可以将参数传递给函数并进行修改:

fn set_42(int: &mut i32) {
    *int += 42;
}

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


更改代码以使用切片失败,并出现一系列错误:

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

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

错误[E0308]:类型不匹配
-->src/main.rs:2:14
|
2 |*slice=&{slice}[1..];
|              ^^^^^^^^^^^^^^^
|              |
|应为片“[i32]”,找到“&[i32]`
帮助:考虑移除借词:{S{} 1…
错误[E0277]:编译时无法知道类型为“[i32]”的值的大小
-->src/main.rs:2:5
|
2 |*slice=&{slice}[1..];
|^^^^^在编译时没有已知的大小
|
=help:trait`std::marker::Sized`未为“[i32]实现`
=注意:要了解更多信息,请访问
=注意:赋值的左侧必须具有静态已知的大小

如果我们尝试使用可变切片(这不是我真正想要的;我不想修改切片中的值,我只想修改切片本身,使其覆盖更小的元素范围)和可变参数,它对原始切片没有影响:

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);
}
:



有没有办法修改作为函数参数的切片?我不想修改切片中的元素;我只想修改切片本身的范围,使其成为更小的“子切片”。

如果需要修改不可变切片

您不能在安全窗口中修改可变切片。当您获取可变切片的子切片时,实际上是从原始切片借用。这意味着子切片的寿命不能超过原始切片

您想要的东西如下所示:

fn pop_front(slice: &mut &mut [i32]) {
    *slice = &mut slice[1..];
}
但是子片
slice[1..]
仅在函数结束前有效,借阅将在哪一点结束,原始片(
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);
}

该程序输出:

[1, 2, 3]

如果需要修改不可变切片

您不能在安全窗口中修改可变切片。当您获取可变切片的子切片时,实际上是从原始切片借用。这意味着子切片的寿命不能超过原始切片

您想要的东西如下所示:

fn pop_front(slice: &mut &mut [i32]) {
    *slice = &mut slice[1..];
}
但是子片
slice[1..]
仅在函数结束前有效,借阅将在哪一点结束,原始片(
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);
}

该程序输出:

[1, 2, 3]
使用部分(我没有想到尝试
&mut&
),我能够在不使用
不安全的
代码的情况下让它工作:

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);
}
:

使用部分(我没有想到尝试
&mut&
),我能够在不使用
不安全的
代码的情况下让它工作:

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);
}
:


正如其他人所说,这里的核心思想是采用
&mut&。。。[T] 
(其中,
mut
或空)并读取/写入内部片。其他答案表明,安全代码中可能存在
&mut&[T]
,不安全代码中可能存在
&mut&mut[T]
,但它们没有解释为什么会有差异。。。而
&mut&mut[T]
也可以使用安全代码

在显式生存期术语中,嵌套引用类似于
&'a mut&'b。。。[T] 
对于一些生命周期
'a
b
,这里的目标是获得
&'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]
而言,安全地执行此操作的方法是从引用中取出具有该
'b
生存期的内部片。这需要跟踪“一个所有者”规则,不借钱,而这种所有权操纵的最佳功能是。它允许我们通过交换一些占位符来提取内部的
&'b mut[T]
,然后我们可以用短版本覆盖它。最好的/唯一的占位符是空数组:对于任何类型的
X
和任何生存期的
'c
,写入
&mut[]
都可以是
&c mut[X]
,因为没有要存储的数据,所以不需要初始化,也没有数据会变得无效。特别是,它可以是a
和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..]
}
(如上所述,我把事情说得比必要的更清楚。)

另见:


正如其他人所说,这里的核心思想是采用
&mut&。。。[T] 
(其中,
mut
或空)并读取/写入内部片。其他答案表明,安全代码中可能存在
&mut&[T]
,不安全代码中可能存在
&mut&mut[T]
,但它们没有解释为什么会有差异。。。而
&mut&mut[T]
也可以使用安全代码

在显式生存期术语中,嵌套引用类似于
&'a mut&'b。。。[T] 
对于一些生命周期
'a
b
,这里的目标是获得
&'b。。。[T] 
,将其切片并将其写入
和'a mut

对于
&'a mut&'b[T]
,这很容易:
&[T]
是复制的,因此编写
*slice=&slice[1..]
将有效地将
&'b[T]
&mu中复制出来
fn pop_front<'a, 'b>(slice: &'a mut &'b mut [i32]) {
    let value: &'b mut [i32] = mem::take(slice);
    *slice = &mut value[1..]
}