如何拥有与父结构具有相同可变性的结构字段?

How to have a struct field with the same mutability as the parent struct?

我正在尝试将一个切片包装在一个结构中,以便我能够可变或不可变地实例化该结构。这是一个最小的例子:

use std::ops::{ Index, IndexMut };

struct Test<'a, T: 'a> {
    inner: &'a[T]
}

impl<'a, T: 'a> Test<'a, T> {
    fn new (inner: &'a[T]) -> Self { Test { inner: inner } }
}

impl<'a, T> Index<usize> for Test<'a, T> {
    type Output = T;
    fn index (&self, i: usize) -> &T { &self.inner[i] }
}

impl<'a, T> IndexMut<usize> for Test<'a, T> {
   fn index_mut (&mut self, i: usize) -> &mut T { &mut self.inner[i] }
}

fn main() {
    let store = [0; 3];
    let test = Test::new (&store);
    println!("{}", test[1]);

    let mut mut_store = [0; 3];
    let mut mut_test = Test::new (&mut mut_store);
    mut_test[1] = 42;
    println!("{}", mut_test[1]);
}

这不编译:"cannot borrow immutable indexed content self.inner[..] as mutable"。

我可以通过将 inner 的定义更改为 &'a mut[T] 类型来编译它,但是 inner 是可变的,即使我不需要它是(在上面的例子中,我必须声明 store 也是可变的,即使 test 是不可变的)。

有没有办法让 inner 的可变性遵循 Test 实例的可变性?

正如问题中所说,这段代码编译:

struct Test<'a, A: 'a> {
  inner: &'a mut A,
}

fn main() {
    let t = Test { inner: &mut 5i32 };

    *t.inner = 9;
}

确实可以改变借用的元素,即使借用的内容是不可变的。在这种情况下,您必须选择保证,同时牢记绑定的可变性始终独立于借用内容的可变性。

目前,我能想到两种可能的解决方案:您可以将借用的内容封装在依赖于self的可变性(Playground,将不再编译)的方法上:

impl<'a, A: 'a> Test<'a, A> {
    fn inner(&self) -> &A {
        self.inner
    }

    fn inner_mut(&mut self) -> &mut A {
        self.inner
    }
}

虽然您仍然需要保留对可变内容的借用,但它不能再从 Test 的不可变绑定中改变。如果你还需要它指向不可变的内容,你应该考虑有两个不同的结构(Playground):

struct Test<'a, A: 'a> {
    inner: &'a A,
}

impl<'a, A: 'a> Test<'a, A> {
    fn inner(&self) -> &A {
        self.inner
    }
}

struct TestMut<'a, A: 'a> {
    inner: &'a mut A,
}

impl<'a, A: 'a> TestMut<'a, A> {
    fn inner(&self) -> &A {
        self.inner
    }

    fn inner_mut(&mut self) -> &mut A {
        self.inner
    }
}

还有第三种选择:用一个枚举专门保留这两种借用。然而,此时,将借用的内容用作可变内容需要 运行 次检查。