Как правильно инициализировать массив фиксированной длины?
У меня проблемы с инициализацией массива фиксированной длины. Все мои попытки до сих пор приводят к одному и тому же использованию возможно неинициализированной переменной: foo_array
"ошибка:
#[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
это черта, но Rust, похоже, не вызывает этого по умолчанию, как конструктор C++.
Как правильно инициализировать массив фиксированной длины? Я хотел бы сделать эффективную инициализацию на месте, а не какую-то копию.
Связанный: Почему свойство Copy необходимо для инициализации массива по умолчанию (struct valueed)?
Связанный: есть ли способ не инициализировать массивы дважды?
3 ответа
Безопасное, но несколько неэффективное решение:
#[derive(Copy, Clone, Debug)]
struct Foo { a: u32, b: u32 }
fn main() {
let mut foo_array = [Foo { a: 10, b: 10 }; 10];
}
Поскольку вы специально запрашиваете решение без копий:
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);
}
}
Самый простой способ - вывести
Copy
на свой тип и инициализируйте массив этим, скопировав элемент
N
раз:
#[derive(Copy)]
struct Foo {
a: u32,
b: u32,
}
let mut foo_array = [Foo { a: 1, b: 2 }; 10];
Если вы хотите избежать копирования, есть несколько вариантов. Вы можете использовать трейт:
let mut foo_array: [Foo; 10] = Default::default();
Однако это ограничено массивами до 32 элементов. С помощью дженериков const теперь стандартная библиотека может предоставлять
Default
для всех массивов. Однако это было бы обратным несовместимым изменением по тонким причинам, над которыми сейчас работают.
А пока вы можете воспользоваться тем, что
const
значения также допускаются в выражениях повторения массива:
const FOO: Foo = Foo { a: 1, b: 2 };
let mut foo_array = [FOO; 10];
Если вы в ночное время, вы можете использовать
array::map
:
#![feature(array_map)]
let mut foo_array = [(); 10].map(|_| Foo::default())
Вы можете использовать arrayvec
ящик:
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!());
}