Artikel ini terutamanya akan membincangkan tentang refleksi dalam Golang, dengan harapan dapat memperoleh pemahaman baharu tentang anda.
Walaupun ramai orang telah menggunakan bahasa Go untuk jangka masa tertentu, malah ada yang selama 1 atau 2 tahun, mereka masih samar-samar tentang refleksi dalam bahasa Go. , saya tidak begitu yakin dalam hati saya. [Cadangan berkaitan: Pergi tutorial video, Pengajaran pengaturcaraan]
Apatah lagi, refleksi hampir tidak pernah digunakan. Anda boleh melakukannya Sememangnya adalah yang paling baik untuk mengendalikannya dengan cara yang paling mudah, paling cekap, berskala dan berprestasi baik. Anda tidak perlu menyalin penggunaan lanjutan secara mekanikal sendiri. Buku ini Kali ini, mari kita lihat dengan lebih dekat cara bermain dengan refleksi
Artikel akan membincangkannya dari lima aspek berikut
Pandangan ringkas, Refleksi ialah keupayaan untuk mengakses dan mengubah suai program itu sendiri semasa program berjalan, sebagai contoh, semasa program berjalan, anda boleh mengubah suai nama medan dan nilai medan program, dan anda juga boleh menyediakan program dengan maklumat capaian antara muka, dsb.
Ini ialah mekanisme yang disediakan dalam bahasa Go Kita boleh Anda boleh melihat banyak penggunaan reflect dalam pustaka awam bahasa
Sebagai contoh, yang biasa digunakan. pakej fmt, Biasa digunakan json Serialization dan deserialization, secara semulajadi perpustakaan gorm yang kami sebutkan tadi juga menggunakan refleksi
Tetapi kenapa kita biasanya menggunakan Bagaimana pula dengan refleksi?
Mengikut kemampuan refleksi, secara semula jadi kerana antara muka yang kami sediakan tidak mengetahui jenis data yang akan datang, jenis data tertentu hanya diketahui apabila program berjalan
Tetapi apabila kami mengekod, kami juga berharap untuk mengesahkan jenis yang diluluskan semasa program dijalankan (seperti pensirilan json) dan beroperasi pada data khusus ini Pada masa ini, kami perlu menggunakan Keupayaan untuk mencerminkan
Jadi di mana sahaja pantulan digunakan, anda boleh melihat antara muka{} Bukankah ia mengejutkan?
Ia adalah tepat kerana kami tidak pasti jenis data yang akan datang, jadi kami mereka bentuknya sebagai antara muka{}. Jika anda tidak pasti tentang ciri dan penggunaan antara muka, anda boleh menyemak artikel sejarah . :
Pertama-tama perhatikan tiga hukum muhasabah yang penting, kita ikut peraturan Tidak akan ada masalah semasa bermain Masalah pelik hanya akan berlaku apabila kita tidak tahu peraturan dan sentiasa mencetuskan klausa
Refleksi boleh berubah. pembolehubah jenis antara muka ditukarkan kepada objek jenis pantulan
Tiga peraturan di atas juga agak mudah difahami Adakah anda masih ingat petunjuk dalam pakej tidak selamat yang kami nyatakan sebelum ini?
Tukar jenis data kami yang biasa digunakan kepada jenis data tertentu dalam pakej (seperti pakej tidak selamat atau pakej mencerminkan), dan kemudian ubah suai data mengikut peraturan dalam pakej
Begitu juga, dengan menukar vest, anda boleh melakukan operasi yang berbeza
Secara amnya, kami akan mempelajari aplikasi asas dahulu, dan kemudian kaji prinsipnya, kaji mengapa ia boleh digunakan dengan cara ini, dan perlahan-lahan anda akan memahami dengan lebih mendalam
Sebenarnya Untuk pembolehubah jenis antara muka yang dinyatakan di sini, kita boleh menghantar pembolehubah mana-mana jenis data, seperti int, float, string ,map, slice, struct
dan seterusnya
Objek jenis pantulan boleh difahami di sini sebagai objek reflect.Type
dan reflect.Value
dalam pakej pantulan pantulan, yang boleh diperolehi melalui fungsi TypeOf dan ValueOf yang disediakan dalam pakej reflect.
di mana reflect.Type
sebenarnya adalah antara muka, yang mengandungi pelbagai antara muka yang perlu dilaksanakan, dan yang menyediakan maklumat berkaitan jenis
Anda boleh melihatnya dalam rajah di bawah reflect.Type
Semua kaedah
sebenarnya adalah struct Menurut struct ini, satu set kaedah juga dikaitkan, yang menyimpan jenis data dan data tertentu Dengan melihat datanya struktur reflect.Value
type Value struct { typ *rtype ptr unsafe.Pointer flag }
kepada unsafe.Pointer
, kemudian mengubah suai datanya dan kemudian menukar Kembali, jika anda tidak biasa dengan penunjuk Go, anda boleh menyemak artikel ini: uintptr
func main() { var demoStr string = "now reflect" fmt.Println("type:", reflect.TypeOf(demoStr)) fmt.Println("value:", reflect.ValueOf(demoStr)) }
ke dalam jenis data khusus kita, kerana terdapat <🎜 yang sepadan dalam reflect.Value
> dan reflect.Value
typ *rtype
ptr unsafe.Pointer
Contohnya, kita boleh mengendalikan
reflect.Value
func main() { var demoStr string = "now reflect" fmt.Println("type:", reflect.TypeOf(demoStr)) fmt.Println("value:", reflect.ValueOf(demoStr)) var res string res = reflect.ValueOf(demoStr).Interface().(string) fmt.Println("res == ",res) }
Untuk Undang-undang 3, ubah suai objek jenis pantulan
dan ValueOf sebenarnya adalah salinan. , maka jika anda mengharapkan untuk mengubah suai nilainya dalam objek jenis pantulan, anda perlu mendapatkan alamat pembolehubah tertentu dan kemudian mengubah suainya Premisnya ialah pembolehubah itu boleh ditulis . Sebagai contoh Anda boleh memahami daripada contoh
func main() { var demoStr string = "now reflect" v := reflect.ValueOf(demoStr) fmt.Println("is canset ", v.CanSet()) //v.SetString("hello world") // 会panic }
Anda boleh memanggil objek
dahulu untuk melihat sama ada ia boleh ditulis, jika ia boleh ditulis. kami akan menulisnya semula. Jika ia tidak boleh ditulis, jangan tulis, jika tidak ia akan panikreflect.Value
CanSet
Kemudian alamat pembolehubah yang diluluskan boleh diubah suai? ?
Tidak salah dengan idea untuk menghantar alamat, tetapi ada sesuatu yang salah dengan cara kita menetapkan nilai, jadi situasi panik di atas juga akan berlaku
Berhati-hati di sini Ia boleh difahami bahawa objek yang dicerminkan secara semula jadi tidak boleh diubah suai > kaedahreflect.Value
reflect.Value
Cara yang lebih rumit sedikit
Selepas mengambil perhatian terhadap kes di atas, anda mungkin berfikir bahawa ia adalah kes yang begitu mudah, dan ia akan menjadi ok sebaik sahaja ia ditunjukkan, tetapi di tempat kerja Jika ia ranap sebaik sahaja ia digunakan, ia bermakna ia masih belum difahami sepenuhnya, menunjukkan bahawa ia belum dihadam Berikut ialah contoh lain di tempat kerja
ialah untuk mengakses
可以看到上述案例运行之后有时可以运行成功,有时会出现 panic 的情况,相信细心的 xdm 就可以看出来,是因为 map 中的 key 是 无序的导致的,此处也提醒一波,使用 map 的时候要注意这一点
看上述代码,是不是就能够明白咱们使用反射去找到对应的数据类型,然后按照数据类型进行处理数据的过程了呢
有需要的话,可以慢慢的去熟练反射包中涉及的函数,重点是要了解其三个规则,对象转换方式,访问方式,以及数据修改方式
那么通过上述案例,可以知道关于反射中数据类型和数据指针对应的值是相当重要的,不同的数据类型能够用哪些函数这个需要注意,否则用错直接就会 panic
来看 TypeOf 的接口中涉及的数据结构
在 reflect 包中 rtype
是非常重要的,Go 中所有的类型都会包含这个结构,所以咱们反射可以应用起来,结构如下
// rtype must be kept in sync with ../runtime/type.go:/^type._type. type rtype struct { size uintptr ptrdata uintptr hash uint32 tflag tflag align uint8 fieldAlign uint8 kind uint8 equal func(unsafe.Pointer, unsafe.Pointer) bool gcdata *byte str nameOff ptrToThis typeOff }
其中可以看到此处的 rtype
的结构保持和 runtime/type.go
一致 ,都是关于数据类型的表示,以及对应的指针,关于这一块的说明和演示可以查看文末的 interface{} 处的内容
从 ValueOf 的源码中,我们可以看到,重要的是 emptyInterface 结构
// emptyInterface is the header for an interface{} value.type emptyInterface struct { typ *rtype word unsafe.Pointer }复制代码
emptyInterface 结构中有 rtype
类型的指针, word 自然是对应的数据的地址了
reflect.Value
对象中的方法也是非常的多,用起来和上述说到的 reflect.Type
接口中的功能类似
关于源码中涉及到的方法,就不再过多的赘述了,更多的还是需要自己多多实践才能体会的更好
殊不知,此处的 reflect.Value
也是可以转换成 reflect.Type
,可以查看源码中 reflect\value.go
的 func (v Value) Type() Type {
其中 reflect.Value
,reflect.Type
,和任意数据类型
可以相互这样来转换
如下图:
至此,关于反射就聊到这里,一些关于源码的细节并没有详细说,更多的站在一个使用者的角度去看反射需要注意的点
关于反射,大多的人是建议少用,因为是会影响到性能,不过如果不太关注这一点,那么用起来还是非常方便的
高级功能自然也是双刃剑,你用不好就会 panic,如果你期望去使用他,那么就去更多的深入了解和一步一步的吃透他吧
大道至简,反射三定律,活学活用
更多编程相关知识,请访问:编程视频!!
Atas ialah kandungan terperinci Artikel yang menerangkan refleksi di Golang secara terperinci. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!