如何拥有与父结构具有相同可变性的结构字段?
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
}
}
还有第三种选择:用一个枚举专门保留这两种借用。然而,此时,将借用的内容用作可变内容需要 运行 次检查。
我正在尝试将一个切片包装在一个结构中,以便我能够可变或不可变地实例化该结构。这是一个最小的例子:
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
}
}
还有第三种选择:用一个枚举专门保留这两种借用。然而,此时,将借用的内容用作可变内容需要 运行 次检查。