【问题标题】:Creating two dimensional arrays in Rust在 Rust 中创建二维数组
【发布时间】:2012-10-24 02:44:49
【问题描述】:

如何在 Rust 中创建一个空的可变二维数组?

这是我迄今为止尝试过的:

let mut state[[u8 * 4] * 4];

这会产生错误

error: expected one of `:`, `;`, `=`, or `@`, found `[`
 --> src/main.rs:2:18
  |
2 |     let mut state[[u8 * 4] * 4];
  |                  ^ expected one of `:`, `;`, `=`, or `@` here

【问题讨论】:

    标签: arrays vector multidimensional-array rust


    【解决方案1】:

    编者注:这个答案早于 Rust 1.0,并且一些概念和语法已经改变。其他答案适用于 Rust 1.0。

    您希望数组的内容是可变的还是保存它的变量?如果你想要可变内容,这对你有用吗?

    let mut state = [[0u8; 4]; 4];
    

    如果您希望变量可变但内容不可变,请尝试以下操作:

    let mut state = [[0u8; 4]; 4];
    

    这有帮助吗?我实际上并没有编译这个,所以语法可能有点不对。

    【讨论】:

    • 是的。这行得通。你知道我如何将这样的数组传递给函数吗?该函数需要更改数组的值。谢谢。
    • 您可以通过两种方式传递值。一种选择是&mut [[u8 * 4] * 4]--- 指向二维固定长度数组的指针。您只需执行&mut state 即可获得这样的指针。
    • 哦,通常有一个像这样的可变变量也允许你改变一个固定长度数组的元素,因为它们是由变量所有的。不幸的是,这个错误 github.com/mozilla/rust/issues/3226> 将暂时阻止您。
    • @NikoMatsakis 谢谢。我让它像这样工作 & [mut [mut u8 * 4] * 4] 作为函数参数。如何获取指向二维数组第一行的指针?
    • 对于未来的访问者:这是针对 1.0 之前的 rust 版本,下面还有另一个答案,其中包含更新的语法。 let mut state = [[0u8; 4]; 4];.
    【解决方案2】:

    显式初始化

    let directions: [[i32; 2]; 4] = [[-1, 0], [0, 1], [0, 1], [1, 0]]
    

    具有相同的值

    let directions: [[i32; 2]; 4] = [[0; 2]; 4];
    

    【讨论】:

      【解决方案3】:

      二维字符串数组的另一个例子:

      fn main() {
          let width = 2;
          let height = 3;
      
          let mut a: Vec<Vec<String>> = vec![vec![String::from(""); width]; height];
      
          for i in 0..height {
              for j in 0..width {
                  let s = format!("{}:{}", i + 1, j + 1);
                  a[i][j] = s;
              }
          }
          println!("{:?}", a);
      }
      

      输出:

      [
        ["1:1", "1:2"],
        ["2:1", "2:2"],
        ["3:1", "3:2"]
      ]
      

      但我不确定为什么我们不能使用此表单:a = [[String::from(""), 2], 3]。我不明白vec![][] 之间的区别。

      【讨论】:

      • 最后一部分看起来像是一个后续问题。
      【解决方案4】:

      好吧,如何创建向量的问题在上面已经得到了适当的解决。下面是代码 sn-p 创建一个二维向量,然后用用户输入填充它:

      use std::io;
      
      fn main(){
          let width = 4;
          let height = 4;
      
          let mut array = vec![vec![0; width]; height];
      
          for i in 0..4 {
              let mut xstr = String::from("");
              io::stdin().read_line(&mut xstr).ok().expect("read error");
              array[i] = xstr
                  .split_whitespace()
                  .map(|s| s.parse().expect("parse error"))
                  .collect();
          }
      
          println!("{:?}", array)
      }
      
      

      【讨论】:

        【解决方案5】:

        如果您愿意安装 crate,ndarray 可以优雅地为您完成。

        use ndarray::Array2;
        let mut array = Array2::zeros((4, 3));
        array[[1, 1]] = 7;
        

        对于一些已经存在的答案,不可能使用非常量维度创建数组。 ndarray 没有这样的问题。您还可以轻松创建多于两个维度的维度。

        您可以在herehere 找到更多详细信息。

        【讨论】:

          【解决方案6】:

          您可以像这样创建一个动态大小的 2D 矢量:

          fn example(width: usize, height: usize) {
              // Base 1d array
              let mut grid_raw = vec![0; width * height];
          
              // Vector of 'width' elements slices
              let mut grid_base: Vec<_> = grid_raw.as_mut_slice().chunks_mut(width).collect();
          
              // Final 2d array `&mut [&mut [_]]`
              let grid = grid_base.as_mut_slice();
          
              // Accessing data
              grid[0][0] = 4;
          }
          

          【讨论】:

          • 我认为它应该是 ...chunks_mut(height)... 假设访问是 grid[0...width-1][0...height-1]
          【解决方案7】:

          如果您在编译时没有已知大小,也可以像这样创建一个二维数组(使用Vec):

          let width = 4;
          let height = 4;
          
          let mut array = vec![vec![0; width]; height];
          

          像这样使用它:

          array[2][2] = 5;
          
          println!("{:?}", array);
          

          输出:

          0 0 0 0
          0 0 0 0
          0 0 5 0
          0 0 0 0

          自 rust 1.0.0 https://doc.rust-lang.org/std/vec/struct.Vec.html 起可用

          【讨论】:

          • 此方法有一个问题:此代码创建了一个指向堆中不同位置的指针(其他 Vec)数组 (Vec),而不是惯用的 C 数组。在某些数组操作上,它可能会导致显着的性能损失。
          • 同意,应该在编译时不知道大小的情况下使用。内存是在堆上动态分配的。
          【解决方案8】:

          初始化:
          二维数组初始化有几种方法:

          1. 对 M(行)和 N(列)使用常量

            const M: usize = 2;
            const N: usize = 4;
            
            let mut grid = [[0 as u8; N] ; M];
            
          2. 带有类型注释的显式声明

            let mut grid: [[u8; 4]; 2] = [[0; 4]; 2];
            

          遍历:
          只读遍历很简单:

          for (i, row) in grid.iter().enumerate() {
              for (j, col) in row.iter().enumerate() {
                  print!("{}", col);
              }
              println!()
          }
          

          for el in grid.iter().flat_map(|r| r.iter()) {
              println!("{}", el);
          }
          

          更新元素:

          for (i, row) in grid.iter_mut().enumerate() {
              for (j, col) in row.iter_mut().enumerate() {
                  col = 1;
              }
          }
          

          【讨论】:

            【解决方案9】:

            在 Rust 1.0 中,以下工作:

            let mut state = [[0u8; 4]; 6];
            state[0][1] = 42;
            

            请注意,内部段的长度是类型的组成部分。例如,您可以引用(并传递)state,如下所示:

            let a: &[[u8; 4]] = &state;
            

            但不能不指定子数组的固定长度。如果您需要可变长度子数组,您可能需要执行以下操作:

            let x: [Box<[u8]>; 3] = [
                Box::new([1, 2, 3]),
                Box::new([4]), 
                Box::new([5, 6])
            ];
            let y: &[Box<[u8]>] = &x;
            

            【讨论】:

            • 请注意,如果您越界访问,则会出现恐慌。感觉不像生锈。
            • 谢谢哈迪,但是“(而且,是的,可变性现在可以工作了)” -> 你将如何访问和改变一个元素?
            • @AndyHayden 在您发表评论后的两年内必须正确实施边界检查,因为我在尝试对外部和内部数组进行越界访问时收到编译时错误。
            【解决方案10】:

            惯用的 C 二维数组使用与访问数组时相同的数组大小顺序声明:

            // Declaration
            int array_2d[8][16]; // An 8 by 16 2D array
            ...
            // Access
            array_2d[0][1] = 5;
            

            在 Rust 中,声明大小是翻转的;要创建一个 8 x 16 的二维数组,语法是:

            // Declaration
            let mut array_2d: [[i32; 16]; 8];
            ...
            // Access (same as idiomatic C. types for added explicitness)
            array_2d[0_usize][1_usize] = 5;
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-12-27
              • 1970-01-01
              • 2011-10-19
              • 1970-01-01
              相关资源
              最近更新 更多