2016-07-15 14 views
8

Ben olmayan bazı copyable türünü ve tüketir ve (belki) onu üreten bir işlevi vardır:Değeri taşıdığım bir kutuyu nasıl yeniden kullanabilirim?

struct NotBox<T> { 
    contents: T 
} 

Biz yapabilirsiniz:

type Foo = Vec<u8>; 

fn quux(_: Foo) -> Option<Foo> { 
    Some(Vec::new()) 
} 

Şimdi kavramsal bir şekilde Box çok benzer bir türünü göz önünde geçici NotBox içeriğini dışarı hareket eder ve onu dönmeden önce geri bir şey koyar bir fonksiyon yazabiliriz:

fn bar(mut notbox: NotBox<Foo>) -> Option<NotBox<Foo>> { 
    let foo = notbox.contents; // now `notbox` is "empty" 
    match quux(foo) { 
     Some(new_foo) => { 
      notbox.contents = new_foo; // we put something back in 
      Some(notbox) 
     } 
     None => None 
    } 
} 

Ben Box es ile çalışır benzer bir işlevi yazmak istiyorum ama derleyici bunu sevmez:

fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> { 
    let foo = *abox; // now `abox` is "empty" 
    match quux(foo) { 
     Some(new_foo) => { 
      *abox = new_foo; // error: use of moved value: `abox` 
      Some(abox) 
     } 
     None => None 
    } 
} 

yerine Some(Box::new(new_foo)) geri dönebilirler ama bu gereksiz tahsisini gerçekleştiren - Zaten benim emrinde bazı bellek var! Bunu önlemek mümkün mü?

Ben de match tabloların kurtulmak istiyorum ama yine derleyici (hatta NotBox versiyonu için) memnun değil:

fn bar(mut notbox: NotBox<Foo>) -> Option<NotBox<Foo>> { 
    let foo = notbox.contents; 
    quux(foo).map(|new_foo| { 
     notbox.contents = new_foo; // error: capture of partially moved value: `notbox` 
     notbox 
    }) 
} 

o geçici bir çözüm mümkün mü?

+3

O'dan daha fazlasını soruyor gibisiniz Burada ne soru var. Maç vs harita biri yeni bir soruya taşınmalı gibi görünüyor. –

+0

İlk kısma cevap verecektim ama fark ettim ki henüz 'Box 'çalışmalarından nasıl geçtiğini anlayamıyorum; Deref veya DerefMut özelliklerine bağlı görünmüyor. Bu yüzden de iyi bir cevap bekliyorum! –

+0

@ChrisEmerson Maç bölümü, benim problemimin en küçük örneğini oluşturmaya çalıştığımda ortaya çıkan bir şeydi, bu yüzden üzerine fazla araştırma yapmadım. Bunun muhtemelen genel soruyla ve "kısmi" işlerin nasıl yürüdüğünü anlamadığım gerçeği ile ilgili olduğunu düşündüm. – mrhania

cevap

8

Yani, Box'dan çıkmak özel bir durum ... şimdi ne olacak?

std::mem modülü, Rust'un bellek güvenliğini deliğe sokmadan (!), Değerleri hareket ettirmek için bir dizi güvenli işlev sunar.ilgi burada swap ve replace şunlardır:

pub fn replace<T>(dest: &mut T, src: T) -> T 

böylece gibi kullanabilirsiniz Hangi:

fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> { 
    let foo = std::mem::replace(&mut *abox, Foo::default()); 

    match quux(foo) { 
     Some(new_foo) => { 
      *abox = new_foo; 
      Some(abox) 
     } 
     None => None 
    } 
} 

o Box ödünç vermez, çünkü o da, map durumunda yardımcı olur:

fn baz(mut abox: Box<Foo>) -> Option<Box<Foo>> { 
    let foo = std::mem::replace(&mut *abox, Foo::default()); 

    quux(foo).map(|new_foo| { *abox = new_foo; abox }) 
} 
+2

Olumsuz olan, Foo: default() 'ın bulunması ve yürütülmesi ucuz olması umar. '>' e geçme önerisi, 'al' diyebilmeniz ve 'Hiçbiri' için ucuz 'varsayılan' olarak nitelendirilebileceği için faydalı olacaktır – Shepmaster

+0

@Shepmaster: Agreed :) Bununla birlikte, Sunulan senaryo ve sadece OP'in daha spesifik kaygıları varsa ayrıntılı olarak açıklayın, aksi halde cevabın kimseye katlanabileceğinden korkuyorum Okumak için ping. –

4

Kutuların dışına taşınması, derleyicide özel kasalıdır. Onlardan bir şeyleri hareket ettirebilirsiniz, ama bir şeyi geri taşıyamazsınız, çünkü hareket etme hareketi de ayrılır. std::ptr::write, std::ptr::read ve std::ptr::replace ile aptalca bir şey yapabilirsiniz, ancak doğru olması zor, çünkü bir şey geçerli olduğunda Box içinde bırakılmalıdır. Sadece tahsisi kabul etmenizi veya bunun yerine Box<Option<Foo>>'a geçmenizi tavsiye ederim.

+1

Rust'la olan en büyük can sıkıntım, görünüşe göre, bu gibi bazı detayların, tartışma konuları dışında veya bazen RFC’lerde geçirilmediği anlaşılıyor. :-(FWIW, [bu ertelenmiş RFC'de bahsedilmiştir] (https://github.com/rust-lang/rfcs/pull/178). –

+2

@ChrisEmerson bence bu durumda, Box'un özel kasası kaldırılması ve önerilen 'DerefMove' özelliğine dönüştürülmesini isteyen bir şey.Çok kirli çamaşırları göstermek istemiyorum ve daha çok yeniden kullanılabilir ve jenerik hale gelebiliyorsa widley içselleştirilmesini istemiyorum. [RFC'nin yeniden başlatıldığını] (https://github.com/rust-lang/rfcs/pull/1646) de – Shepmaster

0

geçici olarak NotBox içeriğini dışarı taşır ve ona kısmen değeriyle almak yapı dışarı taşıyabilirsiniz çünkü var

dönmeden önce geri bir şey koyar bir işlev yazabilirsiniz. Tüm alanlar ayrı değişkenlermiş gibi davranır. Yapı Drop'u uygularsa, bu mümkün değildir, çünkü drop tüm yapının geçerli olmasını gerektirir, her zaman (panik durumunda). Özellikle, neden baz bağımsız değişken olarak Box atması gereken ve neden quux olamaz - geçici çözümü sağlayan gelince

, yeterince bilgi girmediniz? Hangi işlevler sizinki ve hangi değişkenin bir parçası değilsiniz? Gerçek tip Foo nedir? Büyük mü?

En iyi çözüm, Box'u kullanmamaktır.

İlgili konular