web-dev-qa-db-ja.com

スライスタイプのスライス

私は現在、優れた Tour of Go に取り組んでいます。次の解決策で演習の1つ(#45)を終了しました。

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
}

uint8タイプのmakeステートメントを2回使用する必要がある理由がわかりません(スニペットのコメントを参照)。それは冗長に思えますが、他の方法でそれを行う方法がわかりません。

62
harm

Goでこれを行う方法は他にありません。

はい、冗長ですが必要です。 2番目のmake()ステートメントは、最初のステートメントから完全に独立しています。コンパイラはpic[i]から型を推測できるはずだと主張できますが、現時点ではそうではありません。

もう1つのポイント:2番目のケースで型を省略した場合、make()ステートメントはどのように見えますか? make()は、実際の割り当てを行い、必要なlen/capacityを指定できるようにするために必要です。

補足として、スライスの長さを混ぜました。この演習では、コードに入れるとき、dyではなく、dxの長さをトップレベルスライスに設定する必要があります。

33
jimt

明示的にするために、括弧を使用して_[][]uint8_を[]([]uint8)として書き換えることができます:(_uint8_型のスライス)のスライス。

make 組み込み関数を使用すると、タイプTのスライスに対して、make(T, n)は、長さTのタイプnのスライスを返し、容量n

したがって、make([][]uint8, 2)make([]([]uint8), 2)と同等であり、_2_型のスライスの長さと容量が_uint8_のスライスを返します。タイプ_uint8_はそのゼロ値(長さと容量がゼロのnil参照)に初期化されます。

多次元スライスはギザギザで、多次元 ギザギザ配列 に類似しています。

例えば、

_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))
    }
}
_

出力:

_ss:    [][]uint8 [[] []] 2
ss[0]: []uint8 [] 0
ss[1]: []uint8 [] 0
_
34
peterSO