2015-07-13 23 views
7

Genel bir listeyi egzersiz olarak kodlamaya çalışıyorum - sözdizimi tarafından zaten desteklendiğini biliyorum, sadece özyinelemeli bir veri yapısını kodlayıp kodlayamayacağımı görmeye çalışıyorum. Göründüğü gibi yapamam. Sahip olduğum bir yapısal değerin birden fazla alanına erişmek istediğimde bir duvara çarpıyorum. Ben ne yapıyorum"Taşınan değeri kullan" hatası olmadan birden çok yapı alanını bağlama nasıl yapılır?

temelde bu - Bir liste yapacak bir yapı tanımlayın:

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

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

Boş liste sadece List(None) ile temsil edilir. Bu bir hata ile sonlandı yüzden,

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

Tamam "taşındı değerin kullandı:: düğümü" node.tail de bu olduğunu bir açıklama ile

Şimdi, bir listeye eklemek mümkün istiyorum "node.val" konumunda taşındı. Bu anlaşılabilir.

Yani, bir yapının birden fazla alanı kullanmak için yollar aramaya ve bu bulmak: Avoiding partially moved values error when consuming a struct with multiple fields

Büyük, bu yüzden bunu yapacağız:

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

Eh, hayır, atamada hala düğüm devrededir ("error: ntail" de "error: taşınan değer 'düğümünün kullanımı'"). Anlaşılan bu bağlantıda artık işe yaramıyor.

Ayrıca ref kullanarak denedim

:

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

yapısöküm geçer Bu kez, ancak yeni düğümün yaratılması ile başarısız "hata: ödünç içeriğin dışına hareket edemez".

Burada bariz bir şey eksik miyim? Değilse, referans tarafından geçirilmeyen bir yapının birden çok alanına erişmenin uygun yolu nedir?

Yardımlarınız için şimdiden teşekkür ederiz!

DÜZENLEME: Ah, muhtemelen, Rust 1.1 kararlı kullandığımı eklemeliyim.

cevap

5

Box ile biraz garip etkileşim var. Kutuyu açacak bir ara izin istemi eklemeniz gerekir. Ben bu yüzden yeniden adlandırma olmadan kısa formda yapı bozma yazabilirim value için fonksiyon argüman olarak değiştirildi

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

Not.

Try it out in the playground.

+0

Teşekkürler! Bu gerçekten işe yarıyor :) Box neden bu şekilde çalışıyor? Makul bir açıklama var mı? – ebvalaim

+0

Eminim ki, unboxing deref'in bir derleyici büyüsü olduğu gerçeği ile ilgilidir. –

+1

burada ilgili hata: https://github.com/rust-lang/rust/issues/16223 –