Rumah >pembangunan bahagian belakang >Golang >Go s Generics: Menulis Kod Lebih Pintar Yang Berfungsi dengan Pelbagai Jenis
Generik akan datang ke Go, dan ia adalah masalah besar. Saya telah menyelami perubahan yang dicadangkan untuk Go 2, dan saya teruja untuk berkongsi apa yang telah saya pelajari tentang ciri baharu yang berkuasa ini.
Pada asasnya, generik membolehkan kami menulis kod yang berfungsi dengan berbilang jenis. Daripada menulis fungsi berasingan untuk int, rentetan dan jenis tersuai, kita boleh menulis satu fungsi generik yang mengendalikan kesemuanya. Ini membawa kepada kod yang lebih fleksibel dan boleh digunakan semula.
Mari kita mulakan dengan contoh asas. Begini cara kita boleh menulis fungsi "Maks" generik:
func Max[T constraints.Ordered](a, b T) T { if a > b { return a } return b }
Fungsi ini berfungsi dengan mana-mana jenis T yang memenuhi kekangan Tertib. Kami boleh menggunakannya dengan int, apungan, rentetan atau sebarang jenis tersuai yang melaksanakan pengendali perbandingan.
Kekangan jenis adalah bahagian penting dalam pelaksanaan generik Go. Mereka membenarkan kami untuk menentukan operasi jenis generik kami mesti menyokong. Pakej kekangan menyediakan beberapa kekangan yang dipratentukan, tetapi kami juga boleh membuat kekangan sendiri.
Sebagai contoh, kami mungkin mentakrifkan kekangan untuk jenis yang boleh ditukar kepada rentetan:
type Stringer interface { String() string }
Kini kita boleh menulis fungsi yang berfungsi dengan mana-mana jenis yang boleh ditukar kepada rentetan:
func PrintAnything[T Stringer](value T) { fmt.Println(value.String()) }
Salah satu perkara menarik tentang generik Go ialah jenis inferens. Dalam kebanyakan kes, kita tidak perlu menyatakan secara eksplisit parameter jenis apabila memanggil fungsi generik. Pengkompil boleh memikirkannya:
result := Max(5, 10) // Type inferred as int
Ini memastikan kod kami bersih dan boleh dibaca, sambil tetap memberikan faedah generik.
Mari kita masuk ke beberapa wilayah yang lebih maju. Senarai parameter jenis membolehkan kami menentukan hubungan antara parameter berbilang jenis. Berikut ialah contoh fungsi yang menukar antara dua jenis:
func Convert[From, To any](value From, converter func(From) To) To { return converter(value) }
Fungsi ini mengambil nilai apa-apa jenis, fungsi penukar dan mengembalikan nilai yang ditukar. Ia sangat fleksibel dan boleh digunakan dalam banyak senario yang berbeza.
Generik benar-benar bersinar apabila ia berkaitan dengan struktur data. Mari kita laksanakan tindanan generik yang mudah:
type Stack[T any] struct { items []T } func (s *Stack[T]) Push(item T) { s.items = append(s.items, item) } func (s *Stack[T]) Pop() (T, bool) { if len(s.items) == 0 { var zero T return zero, false } item := s.items[len(s.items)-1] s.items = s.items[:len(s.items)-1] return item, true }
Timbunan ini boleh memuatkan sebarang jenis item. Kita boleh membuat tindanan int, rentetan atau struct tersuai, semuanya dengan kod yang sama.
Generik juga membuka kemungkinan baharu untuk corak reka bentuk dalam Go. Sebagai contoh, kita boleh melaksanakan corak pemerhati generik:
type Observable[T any] struct { observers []func(T) } func (o *Observable[T]) Subscribe(f func(T)) { o.observers = append(o.observers, f) } func (o *Observable[T]) Notify(data T) { for _, f := range o.observers { f(data) } }
Ini membolehkan kami mencipta objek yang boleh diperhatikan untuk sebarang jenis data, menjadikannya mudah untuk melaksanakan seni bina dipacu peristiwa.
Apabila memfaktorkan semula kod Go sedia ada untuk menggunakan generik, adalah penting untuk mencapai keseimbangan. Walaupun generik boleh menjadikan kod kami lebih fleksibel dan boleh digunakan semula, mereka juga boleh menjadikannya lebih kompleks dan sukar untuk difahami. Saya mendapati ia selalunya terbaik untuk bermula dengan pelaksanaan konkrit dan hanya memperkenalkan generik apabila kita melihat corak pengulangan yang jelas.
Sebagai contoh, jika kita mendapati diri kita menulis fungsi yang serupa untuk jenis yang berbeza, itu adalah calon yang baik untuk penjanaan. Tetapi jika fungsi hanya digunakan dengan satu jenis, mungkin lebih baik untuk membiarkannya seperti sedia ada.
Satu bidang di mana generik benar-benar bersinar adalah dalam melaksanakan algoritma. Mari lihat pelaksanaan quicksort generik:
func Max[T constraints.Ordered](a, b T) T { if a > b { return a } return b }
Fungsi ini boleh mengisih kepingan apa-apa jenis yang dipesan. Kami boleh menggunakannya untuk mengisih int, apungan, rentetan atau sebarang jenis tersuai yang melaksanakan pengendali perbandingan.
Apabila bekerja dengan generik dalam projek berskala besar, adalah penting untuk memikirkan tentang pertukaran antara fleksibiliti dan semakan jenis masa kompilasi. Walaupun generik membenarkan kami menulis kod yang lebih fleksibel, ia juga boleh memudahkan untuk memperkenalkan ralat masa jalan jika kami tidak berhati-hati.
Satu strategi yang saya dapati berguna ialah menggunakan generik untuk kod perpustakaan dalaman, tetapi mendedahkan jenis konkrit dalam API awam. Ini memberi kami faedah penggunaan semula kod secara dalaman, sambil tetap menyediakan antara muka yang jelas dan selamat jenis kepada pengguna pustaka kami.
Satu lagi pertimbangan penting ialah prestasi. Walaupun pelaksanaan generik Go direka untuk menjadi cekap, masih terdapat beberapa overhed masa jalan berbanding jenis konkrit. Dalam kod kritikal prestasi, mungkin perlu menanda aras pelaksanaan generik vs bukan generik untuk melihat sama ada terdapat perbezaan yang ketara.
Generik juga membuka kemungkinan baharu untuk pengaturcaraan meta dalam Go. Kita boleh menulis fungsi yang beroperasi pada jenis sendiri, bukannya nilai. Sebagai contoh, kita boleh menulis fungsi yang menjana jenis struct baharu pada masa jalan:
type Stringer interface { String() string }
Fungsi ini mencipta jenis struct baharu dengan medan jenis T. Ia merupakan alat yang berkuasa untuk mencipta struktur data dinamik pada masa jalan.
Sebagai pengakhiran, perlu diingat bahawa walaupun generik merupakan ciri yang berkuasa, ia bukanlah penyelesaian terbaik. Kadangkala, antara muka mudah atau jenis konkrit lebih sesuai. Kuncinya ialah menggunakan generik dengan bijak, di mana ia memberikan faedah yang jelas dari segi penggunaan semula kod dan keselamatan jenis.
Generik dalam Go 2 mewakili evolusi bahasa yang ketara. Mereka menyediakan alatan baharu untuk menulis kod yang fleksibel dan boleh digunakan semula sambil mengekalkan penekanan Go pada kesederhanaan dan kebolehbacaan. Sambil kami terus meneroka dan bereksperimen dengan ciri ini, saya teruja untuk melihat cara ia akan membentuk masa depan pengaturcaraan Go.
Pastikan anda melihat ciptaan kami:
Pusat Pelabur | Hidup Pintar | Epos & Gema | Misteri Membingungkan | Hindutva | Pembangunan Elit | Sekolah JS
Tech Koala Insights | Dunia Epok & Gema | Medium Pusat Pelabur | Medium Misteri Membingungkan | Sains & Zaman Sederhana | Hindutva Moden
Atas ialah kandungan terperinci Go s Generics: Menulis Kod Lebih Pintar Yang Berfungsi dengan Pelbagai Jenis. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!