DRYな備忘録

Don't Repeat Yourself.

【Go言語】[]string, []int to []interface{} とかそういうの

「なんかのスライス」を「interface{}のスライス」にしたい。

スライスでなければ、「なんか」を「interface{}」にするのは単に抽象度の増すキャストなので超簡単なわけだけど。

s := "hoge"
i := interface{}(s)

これがスライスとなるとだめ

ss := []string{"aaa","bbb"}
si := []interface{}(ss)

cannot convert ss (type string) to type interface {}

あ、ハイ

理由

Not directly, because they do not have the same representation in memory. It is necessary to copy the elements individually to the destination slice. This example converts a slice of int to a slice of interface{}:

"なんかの"スライスを受けてinterfaceのスライスにしたい

  • 特定のtypeのスライスが来るのであれば、ループ回せばよい
  • "なんかの"スライスが来るのをinterfaceのスライスにするには、やっぱりループが必要
  • しかし[]T[]interface{}で受けることはできないのだから、rangeかけれる保証が必要
  • アサーションするしかないっぽい?
  • しかもrangeかけれる保証がある中でやらなきゃいけないっぽい?

ということでこうなった

http://play.golang.org/p/ao3gq2VHFn

package main

import "fmt"
import "reflect"

func AbstractSlice(arr interface{}) []interface{} {
    dest := []interface{}{}
    switch sl := arr.(type) {
    case []interface{}:
        // こういうのは無理なんですよ
    case string:
        // rangeかけるためにcase内じゃないとダメ
        for _, b := range sl {
            dest = append(dest, b)
        }
    case []string:
        for _, str := range sl {
            dest = append(dest, str)
        }
    case []int:
        for _, i := range sl {
            dest = append(dest, i)
        }
    }
    return dest
}

func main() {

    a := "slice of byte"
    fmt.Println(
        reflect.TypeOf(a),
        reflect.TypeOf(AbstractSlice(a)),
    )

    b := []string{"Hello", "interface"}
    fmt.Println(
        reflect.TypeOf(b),
        reflect.TypeOf(AbstractSlice(b)),
    )

    c := []int{2, 3, 4, 5}
    fmt.Println(
        reflect.TypeOf(c),
        reflect.TypeOf(AbstractSlice(c)),
    )
}

う〜ん...

f:id:otiai10:20150501172923p:plain

DRYな備忘録として