Rust:初始化2D阵列

时间:2019-07-23 03:56:03

标签: arrays memory multidimensional-array rust initialization

我有一个结构,其中包含以下2D数组:

board: [[Option<Rc<dyn Piece>>; SIZE]; SIZE]

顺便说一句,这代表一个国际象棋棋盘,而Piece是一个特征,因此,如果有更好的方法来存储这些数据,我会很感兴趣。

我很难初始化此数组。显而易见的解决方案,将所有内容都设置为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和不安全的锈来创建数组,但是在这个主题上似乎存在一些分歧。在内存中,对其进行迭代以对其进行初始化,然后将其mem::transmuteinto_inner放入常规数组。因为我对不安全的生锈或内存处理不是很熟悉,所以我宁愿不使用这些解决方案,也不完全确定如何调整这些解决方案,这些解决方案适用于我的用例[Vec<u8>; N]

我发现了关于该主题的另一篇文章https://www.joshmcguigan.com/blog/array-initialization-rust/,其中提供了一个带有宏arr!的板条箱,该宏应该是完全安全的。但是,我也不确定这是否是最惯用和最简洁的解决方案。不得不为这样一个小东西安装一个完整的箱子似乎是多余的(尽管这可能是我对语言的感觉,因为我对Rust的最佳实践并不了解)。

我应该使用这些解决方案中的哪一个(如果有的话),如果是前者,我应该如何将其调整为适合数组的阵列?

1 个答案:

答案 0 :(得分:1)

一种方法是使用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();
    }
}