Slicing multi dimensional arrays

You can convert an array to slice this way:

var foo: []usize = undefined;
var array = [_]usize{1,2,3,4,5};
foo = array[0..];

However in two dimensions it does not work:

var foo: [][]usize = undefined;
var array = [_][2]usize{.{1,1}, .{2,2}, .{3,3}};
foo = array[0..][0..];

error: expected type '[][]usize', found '*[3][2]usize'

The problem here is the memory layout. Andrew Kelly on IRC suggested to draw the memory layout before and after, but I have no idea about that (feel free to add if You do), so here is the solution at least. Might help others.

var foo: [][]usize = undefined;
var array = [_][2]usize{.{1,1}, .{2,2}, .{3,3}};

var new: [array.len][]usize = undefined;
for (array) |*sub_array, idx| {
    new[idx] = sub_array[0..];
}

foo = new[0..];

So You have to coerce the subarray one-by-one. Make sure to not return the slice of a stack allocated array as the content of the array may not be available in the outer scope!

I believe that thanks to coercion, you can also write the loop like this:

for (array) |*sub_array, idx| new[idx] = sub_array;

sub_array is a pointer to an array so it can coerce to a slice. In many places in Zig code, I see the style of adding a _ptr suffix to make it clear it’s a pointer and not a plain value, so then:

for (array) |*sub_array_ptr, idx| new[idx] = sub_array_ptr;
1 Like