Rust:初始化二维数组
Rust: Initialize 2D Array
我有一个结构,其中包含以下二维数组:
board: [[Option<Rc<dyn Piece>>; SIZE]; SIZE]
顺便说一句,这是代表一个棋盘,Piece是一个trait,所以如果有更好的方法来存储这个数据,我会很感兴趣。
我在初始化这个数组时遇到困难。显而易见的解决方案,将所有内容设置为 None:
board: [[None; SIZE]; SIZE]
不起作用,因为
error[E0277]: the trait bound `std::rc::Rc<(dyn piece::Piece + 'static)>: std::marker::Copy` is not satisfied
--> src/chessboard.rs:17:21
|
17 | board: [[None; SIZE]; SIZE]
| ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc<(dyn piece::Piece + 'static)>`
|
= note: required because of the requirements on the impl of `std::marker::Copy` for `std::option::Option<std::rc::Rc<(dyn piece::Piece + 'static)>>`
= note: the `Copy` trait is required because the repeated element will be copied
一些研究让我想到了这个关于主题 https://github.com/rust-lang/rust/issues/54542 的 github 问题,尽管大多数解决方案似乎都使用 MaybeUninit
和unsafe rust 在内存中创建数组,遍历它以初始化它,然后 mem::transmute
或 into_inner
将其放入常规数组。因为我对不安全的生锈或处理内存不是很熟悉,所以我宁愿不使用这些解决方案,也不完全确定如何调整这些解决方案,这些解决方案适用于 [Vec<u8>; N]
我的用例。
我发现了另一篇关于这个主题的文章,https://www.joshmcguigan.com/blog/array-initialization-rust/,它提供了一个带有宏的箱子,arr!
这应该是完全安全的。但是,我也不确定这是否是最惯用和最干净的解决方案。必须为这么小的东西安装整个板条箱似乎太过分了(尽管这可能是我对语言的感觉,因为我对 Rust 中的最佳实践知之甚少)。
我应该使用这些解决方案中的哪一个,如果是前者,我应该如何使其适应数组的数组?
一种方法是使用 ndarray
:
use ndarray::Array;
use std::sync::Arc;
trait Piece: std::fmt::Debug {}
#[derive(Debug)]
struct A {}
impl Piece for A {}
#[derive(Debug)]
struct B {}
impl Piece for B {}
fn main() {
const SIZE: usize = 8;
let a = Array::from_shape_fn((SIZE, SIZE), |i| {
if (i.0 + i.1) % 2 == 0 {
Some(Arc::new(A {}) as Arc<dyn Piece>)
} else {
Some(Arc::new(B {}) as Arc<dyn Piece>)
}
});
println!("{:?}", a);
}
但在我看来这不是很地道,我认为你应该更喜欢使用枚举:
use ndarray::Array;
use std::sync::Arc;
trait Action {
fn action(&self);
}
#[derive(Debug)]
struct A {}
impl Action for A {
fn action(&self) {
println!("Action of A");
}
}
#[derive(Debug)]
struct B {}
impl Action for B {
fn action(&self) {
println!("Action of B");
}
}
#[derive(Debug)]
enum Piece {
A(A),
B(B),
}
impl Action for Piece {
fn action(&self) {
match self {
Piece::A(a) => a.action(),
Piece::B(b) => b.action(),
}
}
}
fn main() {
const SIZE: usize = 8;
let a = Array::from_shape_fn((SIZE, SIZE), |i| {
if (i.0 + i.1) % 2 == 0 {
Some(Arc::new(Piece::A(A {})))
} else {
Some(Arc::new(Piece::B(B {})))
}
});
println!("{:?}", a);
for piece in a.iter().flatten() {
piece.action();
}
}
我有一个结构,其中包含以下二维数组:
board: [[Option<Rc<dyn Piece>>; SIZE]; SIZE]
顺便说一句,这是代表一个棋盘,Piece是一个trait,所以如果有更好的方法来存储这个数据,我会很感兴趣。
我在初始化这个数组时遇到困难。显而易见的解决方案,将所有内容设置为 None:
board: [[None; SIZE]; SIZE]
不起作用,因为
error[E0277]: the trait bound `std::rc::Rc<(dyn piece::Piece + 'static)>: std::marker::Copy` is not satisfied
--> src/chessboard.rs:17:21
|
17 | board: [[None; SIZE]; SIZE]
| ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc<(dyn piece::Piece + 'static)>`
|
= note: required because of the requirements on the impl of `std::marker::Copy` for `std::option::Option<std::rc::Rc<(dyn piece::Piece + 'static)>>`
= note: the `Copy` trait is required because the repeated element will be copied
一些研究让我想到了这个关于主题 https://github.com/rust-lang/rust/issues/54542 的 github 问题,尽管大多数解决方案似乎都使用 MaybeUninit
和unsafe rust 在内存中创建数组,遍历它以初始化它,然后 mem::transmute
或 into_inner
将其放入常规数组。因为我对不安全的生锈或处理内存不是很熟悉,所以我宁愿不使用这些解决方案,也不完全确定如何调整这些解决方案,这些解决方案适用于 [Vec<u8>; N]
我的用例。
我发现了另一篇关于这个主题的文章,https://www.joshmcguigan.com/blog/array-initialization-rust/,它提供了一个带有宏的箱子,arr!
这应该是完全安全的。但是,我也不确定这是否是最惯用和最干净的解决方案。必须为这么小的东西安装整个板条箱似乎太过分了(尽管这可能是我对语言的感觉,因为我对 Rust 中的最佳实践知之甚少)。
我应该使用这些解决方案中的哪一个,如果是前者,我应该如何使其适应数组的数组?
一种方法是使用 ndarray
:
use ndarray::Array;
use std::sync::Arc;
trait Piece: std::fmt::Debug {}
#[derive(Debug)]
struct A {}
impl Piece for A {}
#[derive(Debug)]
struct B {}
impl Piece for B {}
fn main() {
const SIZE: usize = 8;
let a = Array::from_shape_fn((SIZE, SIZE), |i| {
if (i.0 + i.1) % 2 == 0 {
Some(Arc::new(A {}) as Arc<dyn Piece>)
} else {
Some(Arc::new(B {}) as Arc<dyn Piece>)
}
});
println!("{:?}", a);
}
但在我看来这不是很地道,我认为你应该更喜欢使用枚举:
use ndarray::Array;
use std::sync::Arc;
trait Action {
fn action(&self);
}
#[derive(Debug)]
struct A {}
impl Action for A {
fn action(&self) {
println!("Action of A");
}
}
#[derive(Debug)]
struct B {}
impl Action for B {
fn action(&self) {
println!("Action of B");
}
}
#[derive(Debug)]
enum Piece {
A(A),
B(B),
}
impl Action for Piece {
fn action(&self) {
match self {
Piece::A(a) => a.action(),
Piece::B(b) => b.action(),
}
}
}
fn main() {
const SIZE: usize = 8;
let a = Array::from_shape_fn((SIZE, SIZE), |i| {
if (i.0 + i.1) % 2 == 0 {
Some(Arc::new(Piece::A(A {})))
} else {
Some(Arc::new(Piece::B(B {})))
}
});
println!("{:?}", a);
for piece in a.iter().flatten() {
piece.action();
}
}