概要
タイトル通り、ベクタを要素に持つ配列を作りたかったが、エラーに悩んだのでメモ。
rustは配列を宣言すると、初期化することが求められるが、その初期化がうまくいかなかった。
やりたいこと
struct Point{
x: f32,
y: f32,
z: f32,
}
fn main() {
let array: [Vec<Point>; 100] = [vec![]; 100];
// Error : the trait bound `Vec<Point>: Copy` is not satisfied
}
Point構造体を確保するベクタを要素として、配列に確保したかった。
-
- 座標情報を持つPoint構造体
x, y, zの座標情報を持つ
格納するベクタVec
点群データを管理したい -> 要素数が未知のため、ベクタで確保
そのベクタを要素とする要素数100の配列
座標により、100つの格子分けをしたかった
格子別に処理を行う際、配列に確保されていれば便利だと考えた
解決策
1 : Default::default()を使う
fn main() {
let array: [Vec<Point>; 10] = Default::default();
// これはOK
// let array: [Vec<Point>; 100] = Default::default();
// これはNG (要素数が32を超えるため)
}
手っ取り早く解決するならこれ。
ただし要素数が32を超えるとNGの模様。
他にはrustのバージョンによって動作しないらしい。
自分の場合、要素数を100にしたかったため、別の方法を探した。
2 : 要素、サイズを const で宣言する (非推奨?)
初期化はできるが要素の追加ができないため、ほぼ意味のないコードになっている
fn main() {
const INIT_ELEMENT: Vec<Point> = vec![];
const ARRAY_SIZE: usize = 100;
// 初期化に使用するパラメータをあらかじめ const で宣言
let array: [Vec<Point>; ARRAY_SIZE] = [INIT_ELEMENT; ARRAY_SIZE];
// これでOK
}
要素数に縛られることなく初期化したいならこれ。
配列を初期化する際、要素の型 (ここではVec)、要素数 (usize) をconstであらかじめ宣言しておき、それを使う。
ただしこちらもバージョンによって動作しないらしい。
追記
constでvecを確保しているので、pushができない。何やってんだこのコード…
3 : unsafe を使い、初期化する
fn main() {
// 1
const SIZE: usize = 100;
let mut uninit_array: [std::mem::MaybeUninit<Vec<Point>>; SIZE];
// 変数が初期化されないことを宣言する
uninit_array = unsafe{
std::mem::MaybeUninit::uninit().assume_init()
};
// 配列分確保のみをする
// 2
for element in &mut uninit_array{
unsafe{std::ptr::write(element.as_mut_ptr(), vec![])};
// 各要素を vec![] で初期化
}
// 3
let mut array = unsafe{std::mem::transmute::<_, [Vec<Point>; SIZE]>(uninit_array)};
// std::mem::MaybeUninit<Vec<Point>> 型から、Vec<Point> に変換する
}
どうやっても safe Rust では再現できない気がしたので、 unsafe Rust で作ってみた。
手順としては、
std::mem::MaybeUninitを使い、配列を初期化なしで宣言する。C で言うint array[10];みたいなもの
その配列を for ループで回し、各要素に初期価値を代入する
std::mem::transmuteを使い、std::mem::MaybeUninit を の配列に変換する
という風に、Cライクに配列を初期化することで対応した。
このようなことでもunsafeを使わないといけないので、メモリ管理を意識しないといけないと分かった。
参考
https://doc.rust-lang.org/std/default/trait.Default.html
https://doc.rust-lang.org/nightly/std/mem/union.MaybeUninit.html#initializing-an-array-element-by-element
https://www.joshmcguigan.com/blog/array-initialization-rust/