如何使struct结构与父结构具有相同的可变性?

时间:2016-11-04 09:56:15

标签: rust mutable

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

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

这不编译:“不能将不可变索引内容self.inner[..]借给可变”。

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

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

1 个答案:

答案 0 :(得分:4)

在问题中也说过,这段代码编译:

ServiceTemplate

即使借用内容是不可变的,也确实可以改变借来的元素。在这种情况下,您必须选择您的保证,同时请记住,绑定的可变性始终与借用内容的可变性无关。

现在,我可以想到两个可能的解决方案:您可以将借用的内容封装在依赖于<Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="control:PaletItem"> <Grid x:Name="RootElement"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Full"> <Storyboard> <ColorAnimation Duration="0:0:0.1" To="Red" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" Storyboard.TargetName="MainGrid" /> </Storyboard> </VisualState> <VisualState x:Name="Empty"> <Storyboard> <ColorAnimation Duration="0:0:0.1" To="Gray" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" Storyboard.TargetName="MainGrid" /> </Storyboard> </VisualState> <VisualState x:Name="Incomplete"> <Storyboard> <ColorAnimation Duration="0:0:0.1" To="Yellow" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" Storyboard.TargetName="MainGrid" /> </Storyboard> </VisualState> <VisualState x:Name="Reserved"> <Storyboard> <ColorAnimation Duration="0:0:0.1" To="Orange" Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" Storyboard.TargetName="MainGrid" /> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid Name="MainGrid" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"> </Grid> </Grid> </ControlTemplate> </Setter.Value> </Setter> 可变性(Playground,将不再编译)的方法上:

[TemplateVisualState(Name = "Empty", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Full", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Incomplete", GroupName = "CommonStates")]
[TemplateVisualState(Name = "Reserved", GroupName = "CommonStates")]
public sealed class PaletItem : Button, INotifyPropertyChanged
{
    // ...
}

虽然你仍然需要借用可变内容,但它不能再从struct Test<'a, A: 'a> { inner: &'a mut A, } fn main() { let t = Test { inner: &mut 5i32 }; *t.inner = 9; } 的不可变绑定中变异。如果您还需要它指向不可变内容,您应该考虑使用两个不同的结构(Playground):

self

还有第三种选择:将两种借用专门用于枚举。但是,在这一点上,使用借来的内容作为可变对象需要运行时检查。