2016-11-04 9 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 «s (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 
    } 
} 

Существует третий вариант: держать оба вида заимствует исключительно с перечислением. Однако на данном этапе использование заимствованного контента как изменчивого требует проверок времени выполнения.