封装可变切片修改

2024-04-13

给定一个函数foo它采用对切片的可变引用。它可以减少切片的长度a = &mut a[1..]。但是,我一直无法弄清楚如何编写一个变异的函数a以同样的方式。

fn foo(mut a: &mut [i32]) {

    a = &mut a[1..];

    inc(&mut a);
}

fn inc<'a: 'b, 'b>(s: &'b mut &'a mut [i32]) {
   *s = &mut s[1..];
}

inc是编写这样一个函数的尝试。但是,它失败了:


Output of rustc nightly (Compiler #1)
error[E0623]: lifetime mismatch
 --> <source>:3:9
  |
2 | fn inc<'a: 'b, 'b>(s: &'b mut &'a mut [i32]) {
  |                       ---------------------
  |                       |
  |                       these two types are declared with different lifetimes...
3 |    *s = &mut s[1..];
  |         ^^^^^^^^^^^ ...but data from `s` flows into `s` here

错误的一个更简单的例子是

fn oops<'a: 'b, 'b>(a: &'b mut &'a mut i32) {
    let _: &'a mut i32 = *a; // error!
}

这里的问题是有a(对某些数据的可变引用)让您mutate(改变)它指向的值,但它不让你move值(不留下任何东西)。在oops,因为一次只能对任何事物有一个可变引用,*a需要移至_,但这留下了*a没有数据和a指向“垃圾”。但无论是谁借的*a to oops期望*a返回时具有价值,因此必须禁止这样做。 (我说“垃圾”是因为这个举动可能并没有真正变异*a,如果我们强制执行它可能不会出错。但如果我们不关心性能,此举原则上可能会破坏*a强制执行“一次可变借用”规则,在这种情况下你就会被淘汰。)

就你而言,index_mut(正在实施[1..]语法)需要&mut [i32], so *s需要移动到函数中。但这留下了*s没有价值,你也不拥有*s,这是非法的。你最终会收回价值并不重要。例如。如果index_mut恐慌,调用者将期望它借给的任何变量有一个值inc,但不会有任何。相比之下,foo does own a,所以离开也没关系a持续时间内无价值index_mut in a = &mut a[1..](编译器可以跟踪拥有的变量何时有值和没有值)。

一种解决方法(不更改界面)是将默认值粘贴到*s当你对其进行操作时。这impl<'a, T> Default for &'a mut[T]提供这个(默认值指向一个空切片),并且std::mem::take包那Default以安全的方式实施。

fn inc<'a: 'b, 'b>(s: &'b mut &'a mut [i32]) {
   *s = &mut std::mem::take(s)[1..];
}

我同意@cdhowie 的写作

fn inc<'a>(s: &'a mut [i32]) -> &'a mut [i32] {
  return s[1..];
}

并要求使用a = inc(a)是一个比inc(&mut a)界面。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

封装可变切片修改 的相关文章

随机推荐