1. ホーム
  2. 行く

[解決済み】インターフェースのスライスを変換するタイプ

2022-04-18 05:32:31

質問

なぜGoは暗黙のうちに []T[]interface{} を暗黙のうちに変換する場合 Tinterface{} . この変換について、私が見逃している何か自明でないことがあるのでしょうか?

func foo([]interface{}) { /* do something */ }

func main() {
    var a []string = []string{"hello", "world"}
    foo(a)
}

go build 文句を言う

関数の引数で、(型[]文字列)を型[]インターフェース{}として使用することはできません。

そして、明示的にやってみても同じことです。 b := []interface{}(a) 文句を言う

<ブロッククオート

(型[]文字列)を型[]インターフェース{}に変換することはできません。

だから、この変換をする必要があるたびに(よく出てくるようです)、次のようなことをしてきました。

b = make([]interface{}, len(a), len(a))
for i := range a {
    b[i] = a[i]
}

これを行う良い方法、またはこれらの変換を支援する標準ライブラリ関数がありますか? 例えばintやstringのリストを受け取ることができる関数を呼び出すたびに、4行の余分なコードを書くのはちょっと馬鹿馬鹿しい気がするのです。

どのように解決するのですか?

Goでは、複雑でコストのかかる操作を構文で隠してはいけないという一般的なルールがあります。を変換して stringinterface{} はO(1)時間で行われる。を変換するのは []stringinterface{} も、スライスが1つの値であることに変わりはないので、O(1)の時間で行われます。しかし []string[]interface{} はO(n)時間です。なぜなら、スライスの各要素を interface{} .

ただし、文字列の変換は例外である。を変換する場合 string との間で []byte または []rune Goは、変換が"syntax"であるにもかかわらず、O(n)の仕事をする。

この変換を代行してくれる標準ライブラリ関数はありません。reflectで作ることはできますが、3行のオプションより遅くなるでしょう。

リフレクションを使った例。

func InterfaceSlice(slice interface{}) []interface{} {
    s := reflect.ValueOf(slice)
    if s.Kind() != reflect.Slice {
        panic("InterfaceSlice() given a non-slice type")
    }

    // Keep the distinction between nil and empty slice input
    if s.IsNil() {
        return nil
    }

    ret := make([]interface{}, s.Len())

    for i:=0; i<s.Len(); i++ {
        ret[i] = s.Index(i).Interface()
    }

    return ret
}

しかし、あなたの最善の方法は、あなたが質問であげたコードの行を使うことです。

b := make([]interface{}, len(a))
for i := range a {
    b[i] = a[i]
}