Slice of slices types

I'm currently working my way through the excellent Tour of Go. I finished one of the exercises (#45) with the following solution:

func Pic(dx, dy int) [][]uint8 {
    pic := make([][]uint8, dy) /* type declaration */
    for i := range pic {
        pic[i] = make([]uint8, dx) /* again the type? */
        for j := range pic[i] {
            pic[i][j] = uint8((i+j)/2)
        }
    }
    return pic
}

I don't understand why I have to use a make statement with the uint8 type twice (see comments in snippet). That seems redundant but I can't figure out how to do it in an other way.


Solution 1:

To be explicit, we can use parentheses to rewrite [][]uint8 as []([]uint8): a slice of (slices of type uint8).

Using the make built-in function, for a slice of type T, make(T, n) returns a slice of type T with length n and capacity n.

Therefore, make([][]uint8, 2) is equivalent to make([]([]uint8), 2), it returns a slice, with length and capacity of 2, of slices of type uint8, where each slice of type uint8 is initialized to its zero value (a nil reference with a length and capacity of zero).

Multi-dimensional slices are jagged and are analogous to multi-dimensional jagged arrays.

For example,

package main

import "fmt"

func main() {
    ss := make([][]uint8, 2) // ss is []([]uint8)
    fmt.Printf("ss:    %T %v %d\n", ss, ss, len(ss))
    for i, s := range ss { // s is []uint8
        fmt.Printf("ss[%d]: %T %v %d\n", i, s, s, len(s))
    }
}

Output:

ss:    [][]uint8 [[] []] 2
ss[0]: []uint8 [] 0
ss[1]: []uint8 [] 0

Solution 2:

There is no other way to do this in Go.

Yes, I agree it is verbose, but necessary. The second make() statement is entirely independent of the first one. It could be argued that the compiler should be able to infer the type from pic[i], but it doesn't at this point.

Another point: how would the make() statement look if you omitted the type in the second case? The make() is still required to do the actual allocation and to be able to specify the required len/capacity.

As a side note, you mixed up the slice lengths. The exercise states the top level slice should have length dy, not dx as you put in your code.