2017-10-19 61 views
14

Bu örnekte neden n1_mut hala geçerli? Option::Some'a taşındı, bu yüzden geçersiz olmamalı mı?İşaretçi hareket ettirildikten sonra neden bir işaretçiye üye atamak hala geçerli?

struct MyRecordRec2<'a> { 
    pub id: u32, 
    pub name: &'a str, 
    pub next: Box<Option<MyRecordRec2<'a>>> 
} 

#[test] 
fn creating_circular_recursive_data_structure() { 
    let mut n1_mut = MyRecordRec2 { 
     id: 1, 
     name: "n1", 
     next: Box::new(None) 
    }; 

    let n2 = MyRecordRec2 { 
     id: 2, 
     name: "n2", 
     next: Box::new(Some(n1_mut)) 
    }; 

    //Why is n1_mut still valid? 
    n1_mut.next = Box::new(Some(n2)); 
} 
şu tanıdık "taşındı değerin kullanılması" ile derleme değil

hata: Bir işaretçi veya olmasın olmak ilgisi yoktur

#[test] 
fn creating_and_freezing_circular_recursive_data_structure() { 
    let loop_entry = { 
     let mut n1_mut = MyRecordRec2 { 
      id: 1, 
      name: "n1", 
      next: Box::new(None), 
     }; 

     let n2 = MyRecordRec2 { 
      id: 2, 
      name: "n2", 
      next: Box::new(Some(n1_mut)), 
     }; 

     n1_mut.next = Box::new(Some(n2)); 

     n1_mut 
    }; 
} 
error[E0382]: use of moved value: `n1_mut` 
    --> src/main.rs:44:9 
    | 
39 |    next: Box::new(Some(n1_mut)), 
    |         ------ value moved here 
... 
44 |   n1_mut 
    |   ^^^^^^ value used here after move 
    | 
    = note: move occurs because `n1_mut` has type `MyRecordRec2<'_>`, which does not implement the `Copy` trait 
+0

İlginç. Bunun bir hata olarak sayılmayacağından emin değilim - daha sonra hafızayı okumak için bir yol olmadığından emin olmadığınıza eminim. Ancak, ham bir işaretçiyi yığına tutturursanız, 'n1Mut.next' öğesinin gerçekten ayarlandığını söyleyebilirsiniz: https://play.rust-lang.org/?gist=d41422bfd142c289667e7c2fb3183be0&version=undefined – trentcl

+0

İlginçtir ki, bu bile mümkün değildir. sonra 'n1_mut.next' kullanın. Ayrıca, bir 'Drop' uygulamasının eklenmesi:" error [E0383]: başlatılmamış yapının "n1_mut" kısmının kısmi yeniden başlatılmasıdır. –

cevap

8

; Bu aynı zamanda çalışır:

#[derive(Debug)] 
struct NonCopy; 

#[derive(Debug)] 
struct Example { 
    name: NonCopy, 
} 

fn main() { 
    let mut foo = Example { 
     name: NonCopy, 
    }; 

    drop(foo); 

    foo.name = NonCopy; 
} 

ben daha önce görmüştüm biliyoruz benzer SO soru, bulamıyorum rağmen bu quote from nikomatsakis bunu anlatır: tartışma, the Rust subreddit üzerinde de vardır

In general moves are tracked at a pretty narrow level of granularity. We intend to eventually permit you to "fill" both fields back in and then use the structure again. I guess that doesn't work today. I have to go look again at the moves code, but I think in general one of the things I'd like to pursue post 1.0 is extending the type system to deal better with things that have been moved from (in particular I want to support moves out of &mut pointers, so long as you restore the value before doing anything fallible). Anyway I think this example more-or-less falls out of treating things in a general way, though you could imagine rules that say "if you move f, you can never again touch any subfields of f without restoring f as a unit".

var ki bağlantılar issue 21232: "borrow-checker allows partial reinit of struct that has been moved away, but no use of it"

Kavramsal olarak, yapının kendisine ek olarak bir yapıda her alan için bir işaret var - Chris Morgan's cardboard box analogy'u düşünmeyi seviyorum. 2014 yılından beri, kimse geçerli olarak tüm yapı işaretleme sağlamak için çaba koymak için rahatsız, Besbelli

drop(foo.name); 
foo.name = NonCopy; 

println!("{:?}", foo); 

: Sen yapı kullanmadan önce çok uzun geri hareket ettikçe sahip olunan yapı tarlasında dışına taşıyabilirsiniz Alanlar tekrar doldurulduktan sonra tekrar.

Gerçekçi olarak, gerçekten tüm bu değişkeni bir kerede atayabileceğinden, bu işleve gerçekten ihtiyacınız yok. Mevcut uygulama, Rust'un sizi iyi görünen bir şey yapmasını engellediği için aşırı derecede güvenli.