2015-07-11 15 views
14

Mam problem z inicjalizacją tablicy o stałej długości. My attempts so far all result in the same "use of possibly uninitialized variable: foo_array" error:Jaki jest właściwy sposób inicjowania macierzy o stałej długości?

#[derive(Debug)] 
struct Foo { a: u32, b: u32 } 

impl Default for Foo { 
    fn default() -> Foo { Foo{a:1, b:2} } 
} 

pub fn main() { 
    let mut foo_array: [Foo; 10]; 

    // Do something here to in-place initialize foo_array? 

    for f in foo_array.iter() { 
     println!("{:?}", f); 
    } 
} 
error[E0381]: use of possibly uninitialized variable: `foo_array` 
    --> src/main.rs:13:14 
    | 
13 |  for f in foo_array.iter() { 
    |    ^^^^^^^^^ use of possibly uninitialized `foo_array` 

I wdrożone cechę Default, ale rdza nie wydaje się nazywają to domyślnie podobny do C++ konstruktora.

Jaki jest właściwy sposób inicjowania macierzy o stałej długości? Chciałbym przeprowadzić wydajną inicjalizację lokalną, a nie jakąś kopię.

pokrewne: Why is the Copy trait needed for default (struct valued) array initialization?

pokrewne: Is there a way to not have to initialize arrays twice?

+2

* Rust nie wydaje się nazywają to domyślnie * - to jest poprawna . Właściwość 'Default' nie jest używana przez kompilator w żaden szczególny sposób. To jest tylko użycie dla programisty. – Shepmaster

Odpowiedz

11

bezpieczny ale somewhat inefficient solution:

#[derive(Copy, Clone, Debug)] 
struct Foo { a: u32, b: u32 } 

fn main() { 
    let mut foo_array = [Foo { a: 10, b: 10 }; 10]; 
} 

Skoro jesteś specjalnie prośbą o a solution without copies:

use std::mem; 
use std::ptr; 

#[derive(Debug)] 
struct Foo { a: u32, b: u32 } 

// We're just implementing Drop to prove there are no unnecessary copies. 
impl Drop for Foo { 
    fn drop(&mut self) { 
     println!("Destructor running for a Foo"); 
    } 
} 

pub fn main() { 
    let array = unsafe { 
     // Create an uninitialized array. 
     let mut array: [Foo; 10] = mem::uninitialized(); 

     for (i, element) in array.iter_mut().enumerate() { 
      let foo = Foo { a: i as u32, b: 0 }; 

      // Overwrite `element` without running the destructor of the old value. 
      // Since Foo does not implement Copy, it is moved. 
      ptr::write(element, foo) 
     } 

     array 
    }; 

    for element in array.iter() { 
     println!("{:?}", element); 
    } 
} 
+0

@ A.B .: Dlaczego pierwsze rozwiązanie jest nieefektywne? (naiwne pytanie, naprawdę nie mam pojęcia ...) –

+0

Jest to nieefektywne w przypadku, gdy musisz zbudować tablicę, w której elementy różnią się od siebie, powiedzmy zestaw kart pokera. W standardowym zestawie 52 kart skończy się 51 niepotrzebnych kopii. –

+4

Jeśli masz szansę na panikę między wywołaniem 'mem :: uninitialized()' a punktem, w którym tablica jest w pełni zainicjalizowana, to ten kod jest zepsuty i nie jest bezpieczny dla paniki. Jeśli Foo jest typem "POD", to jest w porządku. Zauważ, że jak tylko wprowadzisz generyczne (i wywołasz metody cech w pętli inicjalizacyjnej), prawdopodobnie nie będziesz już w stanie zagwarantować braku paniki. – bluss

0

Yo u można użyć arrayvec crate:

Cargo.toml

[package] 
name = "initialize_array" 
version = "0.1.0" 
authors = ["author"] 

[dependencies] 
arrayvec = "0.3.20" 

src/main.rs

extern crate arrayvec; 

use arrayvec::ArrayVec; 
use std::iter; 

#[derive(Clone)] 
struct Foo { 
    a: u32, 
    b: u32, 
} 

fn main() { 
    let foo_array: [Foo; 10] = iter::repeat(Foo { a: 10, b: 10}) 
     .collect::<ArrayVec<_>>() 
     .into_inner() 
     .unwrap_or_else(|_| unreachable!()); 
} 
Powiązane problemy