Reputation: 1836
My intention is to create a dynamic 2D array with multiple rows and columns. How can I achieve that?
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]`
Upvotes: 3
Views: 2804
Reputation: 905
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]
}
}
Upvotes: 4