当前位置:  开发笔记 > 后端 > 正文

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

如何解决《如何修改作为函数参数的切片?》经验,为你挑选了1个好方法。

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

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]

问题:有没有办法修改作为函数参数的切片?我不想修改切片中的元素; 我只想修改切片本身的范围,使其成为一个较小的"子切片".



1> huon..:

正如其他人说,这里的核心思想是采取&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..]
}

(如上所述,我做的事情比必要的更明确.)

推荐阅读
雨天是最美
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有