2015-07-11 2 views
14

У меня возникли проблемы с инициализацией массива с фиксированной длиной. My attempts so far all result in the same "use of possibly uninitialized variable: foo_array" error:Каков правильный способ инициализации массива с фиксированной длиной?

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

Я реализовал Default черты, но ржавчина не кажется, называет это по умолчанию сродни конструктору C++.

Каков правильный способ инициализации массива с фиксированной длиной? Я бы хотел сделать эффективную инициализацию на месте, а не какую-то копию.

Похожие: Why is the Copy trait needed for default (struct valued) array initialization?

Похожие: Is there a way to not have to initialize arrays twice?

+2

* Ржавчина не кажется, называют это по умолчанию * - это правильно , Символ 'Default' не используется компилятором каким-либо особым образом. Это только для программиста. – Shepmaster

ответ

11

Безопасная но 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]; 
} 

Поскольку вы специально просят 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 .: Почему первое решение неэффективно? (наивный вопрос, я действительно не знаю ...) –

+0

Это неэффективно в тех случаях, когда вам нужно построить массив, в котором элементы отличаются друг от друга, например, набор покерных карт. В стандартном наборе 52 карт вы должны будете сделать 51 лишний экземпляр. –

+4

Если у вас есть какая-то вероятность паники между вызовом 'mem :: uninitialized()' и точкой, где массив полностью инициализирован, то этот код нарушается, а не панически безопасен. Если Foo - это тип «POD», тогда все в порядке. Обратите внимание, что как только вы вводите генерики (и вызываете методы trait в цикле инициализации), у вас, вероятно, нет способа гарантировать отсутствие паники. – bluss

0

Yo и может Используйте 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!()); 
} 
Смежные вопросы