2016-11-04 59 views
1

我試圖在一個結構中包裝切片,以便我可以實例化結構可變或不可變。這裏有一個小例子:如何讓結構字段具有與父結構相同的可變性?

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實例的可變性之後?

回答

4

的問題同樣表示,該代碼編譯:

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 
    } 
} 

還有第三個選項:保持這兩種借入的專門用一個枚舉。然而,在這一點上,使用借用的內容作爲mutable需要運行時檢查。

相關問題