Cannot assign to `*myarr[_][_]`, which is behind a `&` reference

I have a 4x4 integer array of arrays A. I want to create 4x4 array A90 where A90 elements are 90 degrees rotated elements of A and I when I change the value of the elements of A90 the corresponding elements in A also change:

let mut a = [
    [ 1, 2, 3, 4],
    [ 5, 6, 7, 8],
    [ 9,10,11,12],
    [13,14,15,16]
];
let mut a90 = [
    [&a[0][3], &a[1][3], &a[2][3], &a[3][3]],
    [&a[0][2], &a[1][2], &a[2][2], &a[3][2]],
    [&a[0][1], &a[1][1], &a[2][1], &a[3][1]],
    [&a[0][0], &a[1][0], &a[2][0], &a[3][0]],
];

*a90[0][0] = 99;

a90 is 90 deg counterclockweis rotated.

Probably easiest to use a crate like ndarray; those data structures support things like swapping dimensions or reversing the order along an axis, and you can do a rotation e.g. like this:

use ndarray::{array, s};

fn main() {
    let mut a = array![
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
        [13, 14, 15, 16]
    ];
    let mut a90 = a.slice_mut(s![.., ..;-1]).reversed_axes();


    dbg!(&a90);
    // [[ 4,  8, 12, 16],
    //  [ 3,  7, 11, 15],
    //  [ 2,  6, 10, 14],
    //  [ 1,  5,  9, 13]]

    a90[(0,0)] = 99;
    a90[(0,1)] = 42;

    dbg!(&a90);
    // [[99, 42, 12, 16],
    //  [ 3,  7, 11, 15],
    //  [ 2,  6, 10, 14],
    //  [ 1,  5,  9, 13]]

    dbg!(&a);
    // [[ 1,  2,  3, 99],
    //  [ 5,  6,  7, 42],
    //  [ 9, 10, 11, 12],
    //  [13, 14, 15, 16]]
}

Rust Playground

Edit: That being said, creating the right kind of [[&mut i32; 4]; 4]-type array isn't out of the question either. Especially with recently-ish stabilized API like <[T; N]>::each_mut:

use std::array;

fn main() {
    let mut a = [
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
        [13, 14, 15, 16]
    ];

    let a90: [[&mut i32; 4]; 4] = {
        let mut iters = a.each_mut().map(|line| line.iter_mut().rev());
        array::from_fn(|_| iters.each_mut().map(|iter| iter.next().unwrap()))  
    };

    dbg!(&a90);
    // [[ 4,  8, 12, 16],
    //  [ 3,  7, 11, 15],
    //  [ 2,  6, 10, 14],
    //  [ 1,  5,  9, 13]]

    *a90[0][0] = 99;
    *a90[0][1] = 42;
    dbg!(&a90);
    // [[99, 42, 12, 16],
    //  [ 3,  7, 11, 15],
    //  [ 2,  6, 10, 14],
    //  [ 1,  5,  9, 13]]

    dbg!(&a);
    // [[ 1,  2,  3, 99],
    //  [ 5,  6,  7, 42],
    //  [ 9, 10, 11, 12],
    //  [13, 14, 15, 16]]
}

Rust Playground


Note that both of these solutions do not allow for interleaved access, i.e. you cannot use a until you're done with using a90. If that isn't what you were looking for, feel free to clarify.

1 Like

Here's one using Cell, which is a little more flexible in that it can do an arbitrary mapping and duplicates:

use std::cell::Cell;

fn main() {
    let mut a = [
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
        [13, 14, 15, 16],
    ];
    let ac = Cell::from_mut(&mut a);
    let a90 = [
        [i(ac, 0, 3), i(ac, 1, 3), i(ac, 2, 3), i(ac, 3, 3)],
        [i(ac, 0, 2), i(ac, 1, 2), i(ac, 2, 2), i(ac, 3, 2)],
        [i(ac, 0, 1), i(ac, 1, 1), i(ac, 2, 1), i(ac, 3, 1)],
        [i(ac, 0, 0), i(ac, 1, 0), i(ac, 2, 0), i(ac, 3, 0)],
    ];

    a90[0][0].set(99);

    println!("{a:?}");
}

fn i(cells: &Cell<[[i32; 4]; 4]>, y: usize, x: usize) -> &Cell<i32> {
    let cell_slice = cells as &Cell<[[i32; 4]]>;
    let slice_of_cells: &[Cell<[i32; 4]>] = cell_slice.as_slice_of_cells();
    let row: &Cell<[i32; 4]> = &slice_of_cells[y];
    let slice_row = row as &Cell<[i32]>;
    let row_slice_cells: &[Cell<i32>] = slice_row.as_slice_of_cells();
    &row_slice_cells[x]
}

Here's one that allows arbitrary mapping and missing elements.

fn main() {
    let mut a = [
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
        [13, 14, 15, 16],
    ];

    let mut placeholder = [[0; 4]; 4];
    let mut place_iter = placeholder.iter_mut().flatten();
    let mut a90: [[_; 4]; 4] =
        std::array::from_fn(|_| std::array::from_fn(|_| place_iter.next().unwrap()));

    for (y, row) in a.iter_mut().enumerate() {
        for (x, i) in row.iter_mut().enumerate() {
            a90[3 - x][y] = i;
        }
    }

    *a90[0][0] = 99;

    println!("{a:?}");
}
1 Like

Ah, yes, arbitrary mapping .. here's another way, involving options, and even "close-ish" in style to the original code (i.e. just write down any arrangement you like using indices).

use std::array;

fn main() {
    let mut a = [
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12],
        [13, 14, 15, 16],
    ];

    let mut a_refs = a.each_mut().map(|line| line.each_mut().map(Some));
    let mut a_ = |i: usize, j: usize| a_refs[i][j].take().unwrap();
    let mut a90 = [
        [a_(0, 3), a_(1, 3), a_(2, 3), a_(3, 3)],
        [a_(0, 2), a_(1, 2), a_(2, 2), a_(3, 2)],
        [a_(0, 1), a_(1, 1), a_(2, 1), a_(3, 1)],
        [a_(0, 0), a_(1, 0), a_(2, 0), a_(3, 0)],
    ];

    dbg!(&a90);
    // [[ 4,  8, 12, 16],
    //  [ 3,  7, 11, 15],
    //  [ 2,  6, 10, 14],
    //  [ 1,  5,  9, 13]]

    *a90[0][0] = 99;
    *a90[0][1] = 42;
    dbg!(&a90);
    // [[99, 42, 12, 16],
    //  [ 3,  7, 11, 15],
    //  [ 2,  6, 10, 14],
    //  [ 1,  5,  9, 13]]

    dbg!(&a);
    // [[ 1,  2,  3, 99],
    //  [ 5,  6,  7, 42],
    //  [ 9, 10, 11, 12],
    //  [13, 14, 15, 16]]
}

Rust Playground

2 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.