Sample Code
func SplitSlice(list interface{}, size int) ([]interface{}, error) {
if size <= 0 {
return nil, fmt.Errorf("size need positive number")
}
// sliceかどうかのチェック
if reflect.TypeOf(list).Kind() != reflect.Slice {
return nil, fmt.Errorf("list must be slice")
}
var result = []interface{}{}
var v = reflect.ValueOf(list)
for i := 0; i < v.Len(); i += size {
if i+size <= v.Len() {
result = append(result, v.Slice(i, i+size).Interface())
} else {
result = append(result, v.Slice(i, v.Len()).Interface())
}
}
return result, nil
}
解説のようなもの
任意の型のSliceを指定したサイズごとに分割する、と考えると
func SplitSlice(src []interface{}) [][]interface{}
のようにinterface{}
型のSliceを受け取ってinterface{}
型の2次元Sliceを返すようなインタフェイスを考えてしまいがちですが、
実際にはこのような関数はコンパイルが通りません.
なぜなら[]string
型はinterface{}
型ではあっても[]interface{}
型ではないからです.
なので, 関数の定義時点ではinterface{}
として受け取り
// sliceかどうかのチェック
if reflect.TypeOf(list).Kind() != reflect.Slice {
return nil, fmt.Errorf("src must be slice")
}
とreflectパッケージの機能を使い, 引数がsliceであることを確認後
var v = reflect.ValueOf(list)
for i := 0; i < v.Len(); i += size {
if i+size <= v.Len() {
result = append(result, v.Slice(i, i+size).Interface())
} else {
result = append(result, v.Slice(i, v.Len()).Interface())
}
}
reflect.Value型に変換後, 用意されたLen
メソッドとSlice
メソッドを使って分割していくことになります.
なお, この関数から返される値の方はinterface{}
なので, 使う場合は
一度元の型にキャストし直してください.