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{}なので, 使う場合は
一度元の型にキャストし直してください.