简体   繁体   English

Rust:初始化2D阵列

[英]Rust: Initialize 2D Array

I have a struct, which contains the following 2D array: 我有一个结构,其中包含以下2D数组:

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

Incidentally, this is representing a chess board, and Piece is a trait, so if there is a better way to store this data, I would be interested. 顺便说一句,这代表一个国际象棋棋盘,而Piece是一个特征,因此,如果有更好的方法来存储此数据,我会很感兴趣。

I am having difficulty initializing this array. 我在初始化此数组时遇到困难。 The obvious solution, setting everything to None: 显而易见的解决方案,将所有内容都设置为None:

board: [[None; SIZE]; SIZE]

doesn't work because 不起作用,因为

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

Some research led me to this github issue on the topic, https://github.com/rust-lang/rust/issues/54542 , where there seems to be some disagreement about the topic, though most solutions appear to use MaybeUninit and unsafe rust to create the array in memory, iterate over it to initialize it, then either mem::transmute or into_inner it into the regular array. 一些研究使我想到了关于该主题的github问题https://github.com/rust-lang/rust/issues/54542 ,尽管大多数解决方案似乎都使​​用MaybeUninit并且不安全,但是在该主题上似乎存在一些分歧rust在内存中创建数组,对其进行迭代以将其初始化,然后将mem::transmute into_innerinto_inner放入常规数组。 Because I am not very familiar with unsafe rust or dealing with memory, I'd rather not use these solutions, and am not entirely certain how to adapt those solutions, which are for [Vec<u8>; N] 因为我对不安全的生锈或内存处理不是很熟悉,所以我宁愿不使用这些解决方案,也不完全确定如何适应这些解决方案,这些解决方案适用于[Vec<u8>; N] [Vec<u8>; N] to my use case. [Vec<u8>; N]到我的用例。

I found another article on the subject, https://www.joshmcguigan.com/blog/array-initialization-rust/ , which presents a crate with a macro, arr! 我找到了关于该主题的另一篇文章, 网址为https://www.joshmcguigan.com/blog/array-initialization-rust/ ,其中提供了一个带有宏arr!的板条箱arr! which is supposed to be entirely safe. 这应该是完全安全的。 However, I am also not certain if this is the most idiomatic and clean solution. 但是,我也不确定这是否是最惯用和最简洁的解决方案。 Having to install an entire crate for such a small thing seems excessive (though that may be my feelings from languages, as I don't know much about the best practices in Rust). 不得不为这样一个小东西安装一个完整的箱子似乎是多余的(尽管这可能是我对语言的感觉,因为我对Rust的最佳实践并不了解)。

Which, if either, of these solutions should I use, and if it is the former, how should I adapt it to arrays of arrays? 如果应该使用这些解决方案中的哪一个,如果是前者,则应如何使它适应数组阵列?

One way would be to use ndarray : 一种方法是使用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);
}

But that not very idiomatic in my opinion, I think you should prefer use an enum: 但这在我看来不是很惯用,我认为您应该使用枚举:

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();
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM