2015-07-11 15 views
14

Non riesco a inizializzare un array a lunghezza fissa. My attempts so far all result in the same "use of possibly uninitialized variable: foo_array" error:Qual è il modo corretto per inizializzare un array a lunghezza fissa?

#[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` 

ho implementato il Default tratto, ma Rust non sembra chiamare questo di default simile a un costruttore C++.

Qual è il modo corretto per inizializzare un array a lunghezza fissa? Mi piacerebbe fare un'inizializzazione sul posto efficiente piuttosto che una sorta di copia.

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

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

+2

* Rust non sembra chiamare questo di default * - che è corretto . Il carattere 'Default' non è usato dal compilatore in alcun modo speciale. È solo l'uso è per il programmatore. – Shepmaster

risposta

11

La cassaforte ma 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]; 
} 

Dal momento che si sta chiedendo esplicitamente per 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 .: Perché la prima soluzione è inefficiente? (domanda ingenua, non ne ho idea ...) –

+0

È inefficiente nei casi in cui è necessario costruire un array in cui gli elementi differiscono l'uno dall'altro, ad esempio set di carte da poker. In un set di 52 carte standard finirai per fare 51 copie inutili. –

+4

Se avete qualche possibilità di panico tra la chiamata a 'mem :: uninitialized()' e il punto in cui la matrice è completamente inizializzata, allora questo codice è rotto e non è sicuro dal panico. Se Foo è un tipo "POD", allora va bene, però. Notate che non appena introducete i generici (e chiamate i metodi dei tratti nel ciclo di inizializzazione), probabilmente non avrete più modo di garantire la mancanza di panico. – bluss

0

Yo u possibile utilizzare il 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!()); 
} 
Problemi correlati