2015-07-13 8 views
7

Я пытаюсь закодировать общий список как упражнение - я знаю, что он уже поддерживается синтаксисом, я просто пытаюсь проверить, могу ли я закодировать рекурсивную структуру данных. Как оказалось, я не могу. Я нажимаю на стену, когда хочу получить доступ к нескольким полям имеющейся ценности структуры.Как связать несколько структурных полей, не получив ошибку «use move value»?

Что я делаю, в основном это - я определить структуру, которая будет содержать список:

struct ListNode<T> { 
    val: T, 
    tail: List<T> 
} 

struct List<T>(Option<Box<ListNode<T>>>); 

Пустой список только представленного List(None).

Теперь я хочу, чтобы иметь возможность добавить к списку:

impl<T> List<T> { 
    fn append(self, val: T) -> List<T> { 
     match self { 
      List(None) => List(Some(Box::new(ListNode { val: val, tail: List(None) }))), 
      List(Some(node)) => List(Some(Box::new(ListNode { val: node.val, tail: node.tail.append(val) }))) 
     } 
    } 
} 

Ok, так что не может с ошибкой «используется перемещаемым значение: узел» в node.tail с объяснением, что это было перемещен в «node.val». Это понятно.

Итак, я смотрю на способы использования более одного поля из структуры, и я нахожу это: Avoiding partially moved values error when consuming a struct with multiple fields

Великий, так что я буду делать, что:

List(Some(node)) => { 
    let ListNode { val: nval, tail: ntail } = *node; 
    List(Some(Box::new(ListNode { val: nval, tail: ntail.append(val) }))) 
} 

Ну, Нету, неподвижный узел перемещается при назначении («ошибка: использование перемещенного значения« узел »в« хвосте: ntail »). По-видимому, это больше не работает, как в ссылке.

Я также попытался с помощью рефов:

List(Some(node)) => { 
    let ListNode { val: ref nval, tail: ref ntail } = *node; 
    List(Some(Box::new(ListNode { val: *nval, tail: (*ntail).append(val) }))) 
} 

На этот раз деконструкция проходит, а создание нового узла терпит неудачу с «ошибкой: не может выйти из заимствованного контента».

Я пропустил что-то очевидное здесь? Если нет, то каков правильный способ доступа к нескольким полям структуры, которые не передаются по ссылке?

Заранее благодарим за любую помощь!

EDIT: О, я, наверное, должен добавить, что я использую стабилизатор Rust 1.1.

ответ

5

Существует некоторое странное взаимодействие с Box. Вам нужно добавить промежуточный оператор let, который разворачивает ящик.

List(Some(node)) => { 
    let node = *node; // this moves the value from the heap to the stack 
    let ListNode { val, tail } = node; // now this works as it should 
    List(Some(Box::new(ListNode { val: val, tail: tail.append(value) }))) 
} 

Обратите внимание, что я переименовал свой аргумент функции в value, так что я мог бы написать деструктурирующие в короткой форме без переименования.

Try it out in the playground.

+0

Спасибо! Это действительно работает :) Почему Box работает именно так? Есть ли разумное объяснение? – ebvalaim

+0

Я уверен, что это связано с тем, что unboxing deref - это некоторая магия компилятора. –

+1

вот соответствующая ошибка: https://github.com/rust-lang/rust/issues/16223 –