我正在尝试将一个切片包装在一个结构中,以便我能够可变地或不可变地实例化该结构。这是一个最小的例子:
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
实例的可变性?
答案 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
还有第三种选择:将两种借用专门用于枚举。但是,在这一点上,使用借来的内容作为可变对象需要运行时检查。