GoがT
を[]T
に暗黙的に変換するのに、Goが[]interface{}
をinterface{}
に暗黙的に変換しない理由を知りたいです。私が見逃しているこの変換について重要なことはありますか?
例:
func foo([]interface{}) { /* do something */ }
func main() {
var a []string = []string{"hello", "world"}
foo(a)
}
go build
の苦情
関数の引数では、タイプ[] interface {}として(type [] string)を使用できません
そして、私がそれを明示的にしようとすると、同じこと:b := []interface{}(a)
が不平を言います
(タイプ[] string)をタイプ[] interface {}に変換できません
そのため、この変換を行う必要があるたびに(多くの場合に発生するようです)、私はこのようなことをしています。
b = make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}
これを行うより良い方法、またはこれらの変換を支援する標準ライブラリ関数はありますか?リストを取得できる関数を呼び出すたびに4行のコードを追加するのは、ばかげているようです。 intまたは文字列。
Goには、構文が複雑でコストのかかる操作を隠さないという一般的なルールがあります。 string
からinterface{}
への変換は、O(1)時間で行われます。スライスはまだ1つの値であるため、[]string
からinterface{}
への変換もO(1)時間で行われます。ただし、スライスの各要素を[]string
に変換する必要があるため、[]interface{}
をinterface{}
に変換するとO(n)時間になります。
この規則の1つの例外は、文字列の変換です。 string
を[]byte
または[]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")
}
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]
}
欠けているのは、T
の値を保持するT
とinterface{}
がメモリ内で異なる表現を持っているため、簡単に変換できないことです。
タイプT
の変数は、メモリ内の単なる値です。関連する型情報はありません(Goでは、すべての変数は実行時ではなくコンパイル時に認識される単一の型を持ちます)。メモリ内では次のように表されます。
タイプT
の変数を保持するinterface{}
は、このようにメモリ内で表されます
T
へのポインターあなたの元の質問に戻ります:なぜgoは[]T
を[]interface{}
に暗黙的に変換しないのですか?
[]T
を[]interface{}
に変換するには、メモリ内のレイアウトが完全に異なるため、interface {}
値の新しいスライスの作成が必要になります。
公式の説明は次のとおりです。 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
}
代わりにinterface{}
を試してください。スライスとしてキャストバックするには、試してください
func foo(bar interface{}) {
s := bar.([]string)
// ...
}
interface{}
を任意の型に変換します。
構文:
result := interface.(datatype)
例:
var employee interface{} = []string{"Jhon", "Arya"}
result := employee.([]string) //result type is []string.