3

My intention is to create a dynamic 2D array with multiple rows and columns. How can I achieve that?

Attempted solution

The following line of code works but the array ends up having only a single row.

let matrix: &mut [&mut [i32]] = &mut [&mut [0; 3]];

In order to create an array with 3 rows instead of one I tried the following piece of code but it produced a compile time error.

let matrix: &mut [&mut [i32]] = &mut [&mut [0; 3]; 3];
mismatched types

expected slice `[&mut [i32]]`, found array `[&mut [{integer}; 3]; 3]`

note: expected mutable reference `&mut [&mut [i32]]`
         found mutable reference `&mut [&mut [{integer}; 3]; 3]`rustc(E0308)
main.rs(7, 17): expected due to this
main.rs(7, 37): expected slice `[&mut [i32]]`, found array `[&mut [{integer}; 3]; 3]`
1
  • 2
    Depends what you mean by dynamic and 2D array. But a Vec<Vec<i32>> is probably what you want. Its an array of arrays, rather than a 2D array. Alternatively you might want to look on crates.io. Commented May 30, 2021 at 12:50

1 Answer 1

4

Based on your question it looks like you're trying to use a matrix object. There are multiple ways to do that in rust:

Compile-Time matrices: Using const generics it's now very easy to define the matrix object with an array of arrays:

pub struct Matrix<T, const ROWS: usize, const COLS: usize> {
    data: [[T; COLS]; ROWS],
}

impl<T, const ROWS: usize, const COLS: usize> Matrix<T, ROWS, COLS> {
    pub fn new(data: [[T; COLS]; ROWS]) -> Self {
        Self { data }
    }
}

impl<T, const ROWS: usize, const COLS: usize> Index<(usize, usize)> for Matrix<T, ROWS, COLS> {
    type Output = T;

    fn index(&self, index: (usize, usize)) -> &Self::Output {
        &self.data[index.0][index.1]
    }
}

Here, the amount of rows and columns are hard-coded into the data-type. So to resize you need to a create a new object and all types must be known (defined) at compile time.

Dynamic matrices:

If you want run-time (dynamic) sizing, the simplest solution is to use a vector of vectors:

pub struct Matrix<T> {
    data: Vec<Vec<T>>,
}

impl<T> Matrix<T> {
    pub fn new(data: Vec<Vec<T>>) -> Self {
        Self { data }
    }
}

impl<T> Index<(usize, usize)> for Matrix<T> {
    type Output = T;

    fn index(&self, index: (usize, usize)) -> &Self::Output {
        &self.data[index.0][index.1]
    }
}

Note that since vectors are pointers to memory on the heap, the items won't usually be contiguous in memory.

You can build contiguous dynamic matrices by using a single vector and indices to map to chunks of it:

pub struct Matrix<T> {
    rows: usize,
    cols: usize,
    data: Vec<T>,
}

impl<T> Matrix<T> {
    pub fn new(rows: usize, cols: usize, data: Vec<T>) -> Self {
        assert_eq!(rows * cols, data.len());
        Self { rows, cols, data }
    }
}

impl<T> Index<(usize, usize)> for Matrix<T> {
    type Output = T;

    fn index(&self, index: (usize, usize)) -> &Self::Output {
        &self.data[index.0 * self.cols + index.1]
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.