262

[]TGo が に暗黙的に変換される[]interface{}ときに、なぜ Go が暗黙的に に変換されないのか興味がTありinterface{}ます。この変換について、私が見逃している重要なことはありますか?

例:

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

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

go build文句を言う

関数の引数で (type []string) を type []interface {} として使用することはできません

そして、私が明示的にそれをやろうとすると、同じこと:b := []interface{}(a)文句を言う

(type []string) を type []interface {} に変換できません

したがって、この変換を行う必要があるたびに (これは頻繁に発生するようです)、次のようなことを行ってきました。

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

これを行うためのより良い方法、またはこれらの変換を支援する標準ライブラリ関数はありますか? int や文字列などのリストを取得できる関数を呼び出すたびに、4 行の余分なコードを記述するのはばかげているように思えます。

4

8 に答える 8

288

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

この規則の 1 つの例外は、文字列の変換です。stringa[]byteまたは aとの間でa を変換する場合[]rune、変換が「構文」であっても、Go は O(n) を実行します。

この変換を行う標準ライブラリ関数はありません。リフレクトを使用して作成することもできますが、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]
}
于 2012-10-05T22:16:52.627 に答える
70

あなたが見逃しているのは、Tinterface{}の値を保持するものはT、メモリ内に異なる表現を持っているため、簡単に変換できないということです。

型の変数はT、メモリ内の値にすぎません。関連付けられた型情報はありません (Go では、すべての変数は、実行時ではなくコンパイル時に認識される単一の型を持ちます)。メモリ内では次のように表されます。

  • 価値

タイプのinterface{}変数を保持することは、Tこのようにメモリ内で表されます

  • タイプへのポインタT
  • 価値

元の質問に戻って、なぜ go が暗黙的に に変換[]Tされないの[]interface{}ですか?

に変換[]Tするには、値[]interface{}の新しいスライスを作成する必要がありinterface {}ます。これは、メモリ内レイアウトが完全に異なるため、重要な操作です。

于 2012-10-06T08:12:52.933 に答える
19

公式の説明は次のとおりです: https://github.com/golang/go/wiki/InterfaceSlice

var dataSlice []int = foo()
var interfaceSlice []interface{} = make([]interface{}, len(dataSlice))
for i, d := range dataSlice {
    interfaceSlice[i] = d
}
于 2016-10-20T23:03:59.803 に答える
6

interface{}代わりに試してください。スライスとしてキャストバックするには、試してください

func foo(bar interface{}) {
    s := bar.([]string)
    // ...
}
于 2012-10-05T21:56:23.463 に答える
-3

interface{}任意の型に変換します。

構文:

result := interface.(datatype)

例:

var employee interface{} = []string{"Jhon", "Arya"}
result := employee.([]string)   //result type is []string.
于 2019-03-25T13:06:29.053 に答える