LoginSignup
0
0

More than 5 years have passed since last update.

小テクニック:sliceを分割する

Posted at

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
}

go-playground

解説のようなもの

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

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0