Saya ingin tahu mengapa Go tidak secara implisit dikonversi []T
ke []interface{}
ketika secara implisit dikonversi T
ke interface{}
. Apakah ada sesuatu yang tidak sepele tentang konversi ini yang saya lewatkan?
Contoh:
func foo([]interface{}) { /* do something */ }
func main() {
var a []string = []string{"hello", "world"}
foo(a)
}
go build
mengeluh
tidak dapat menggunakan (ketik [] string) sebagai tipe [] antarmuka {} dalam argumen fungsi
Dan jika saya mencoba melakukannya secara eksplisit, hal yang sama: b := []interface{}(a)
mengeluh
tidak dapat mengonversi string (ketik []) ke antarmuka [] {}
Jadi setiap kali saya perlu melakukan konversi ini (yang tampaknya banyak muncul), saya telah melakukan sesuatu seperti ini:
b = make([]interface{}, len(a), len(a))
for i := range a {
b[i] = a[i]
}
Apakah ada cara yang lebih baik untuk melakukan ini, atau fungsi perpustakaan standar untuk membantu dengan konversi ini? Tampaknya konyol untuk menulis 4 baris kode tambahan setiap kali saya ingin memanggil fungsi yang dapat mengambil daftar misalnya int atau string.
sumber
Jawaban:
Di Go, ada aturan umum bahwa sintaksis tidak boleh menyembunyikan operasi yang kompleks / mahal. Konversi a
string
ke ainterface{}
dilakukan dalam O (1) waktu. Konversi a[]string
ke ainterface{}
juga dilakukan dalam waktu O (1) karena irisan masih satu nilai. Namun, mengubah a[]string
menjadi waktu[]interface{}
O (n) karena setiap elemen slice harus dikonversi menjadiinterface{}
.Satu-satunya pengecualian untuk aturan ini adalah mengonversi string. Saat mengonversi a
string
ke dan dari a[]byte
atau a[]rune
, Go do O (n) berfungsi meskipun konversi adalah "sintaksis".Tidak ada fungsi perpustakaan standar yang akan melakukan konversi ini untuk Anda. Anda dapat membuat satu dengan pantulan, tetapi itu akan lebih lambat dari opsi tiga baris.
Contoh dengan refleksi:
Opsi terbaik Anda adalah menggunakan baris kode yang Anda berikan dalam pertanyaan Anda:
sumber
map
s terlalu btw.channels
.Converting a []string to an interface{} is also done in O(1) time
?Hal yang Anda lewatkan adalah bahwa
T
daninterface{}
yang memiliki nilaiT
memiliki representasi yang berbeda dalam memori sehingga tidak dapat dikonversi secara sepele.Variabel tipe
T
hanya nilainya dalam memori. Tidak ada informasi tipe terkait (dalam Go setiap variabel memiliki tipe tunggal yang diketahui pada waktu kompilasi bukan pada saat run time). Itu direpresentasikan dalam memori seperti ini:Sebuah
interface{}
memegang variabel jenisT
direpresentasikan dalam memori seperti iniT
Jadi kembali ke pertanyaan awal Anda: mengapa pergi tidak secara implisit dikonversi
[]T
ke[]interface{}
?Konversi
[]T
ke[]interface{}
akan melibatkan pembuatan irisaninterface {}
nilai baru yang merupakan operasi non-sepele karena tata letak dalam memori benar-benar berbeda.sumber
Berikut adalah penjelasan resmi: https://github.com/golang/go/wiki/InterfaceSlice
sumber
[]interface
ke tipe yang saya harapkan[]map[string]interface{}
?Coba
interface{}
saja. Untuk membuang kembali sebagai irisan, cobasumber
bar
untuk menafsirkannya sebagai "sepotong jenis apa pun"? Perhatikan bahwa ketiganya menciptakan[]interface{}
, bukan[]string
atau sepotong tipe beton lainnya.func foo(bar []string) { /* ... */ }
interface{}
akan membuat kompiler tidak mengeluh ketika melewati argumen seperti padafoo(a)
. Dia bisa menggunakan refleksi atau mengetik switching ( golang.org/doc/effective_go.html#type_switch ) di dalamnyafoo
.Konversikan
interface{}
ke dalam jenis apa pun.Sintaksis:
Contoh:
sumber
invalid type assertion: potato.([]string) (non-interface type []interface {} on left)
Jika Anda membutuhkan lebih banyak korslet kode, Anda dapat membuat tipe baru untuk helper
kemudian
sumber