Artikel ini diperkenalkan oleh lajur tutorial golang untuk memperkenalkan soalan temu bual tentang gelung Go for Saya tertanya-tanya sejauh mana anda tahu tentang gelung for. Di bawah ini saya akan bercakap tentang isu-isu berkaitan secara terperinci. Saya harap ia akan membantu rakan-rakan yang memerlukannya!
Saya tidak tahu berapa banyak soalan temu duga Go dan kebocoran yang berkaitan dengan untuk gelung. Hari ini saya melihat dengan lebih dekat pada hujung minggu dan menemui pentakrifan semula untuk semantik pembolehubah gelung.
Tahun tegar terkenal Russ Cox berkata dia telah mengkaji isu ini dan berkata bahawa pengalaman sepuluh tahun menunjukkan bahawa kos semantik semasa adalah sangat tinggi.
Masalah
Kes 1: Dapatkan watak alamat
Dalam bahasa Go, kami menulis Bila menggunakan pernyataan for, kadangkala hasil larian dan tekaan tidak konsisten. Contohnya, kod kes pertama di bawah:
var all []*Itemfor _, item := range items { all = append(all, &item) }
Adakah terdapat masalah dengan kod ini? Apakah yang disimpan dalam pembolehubah item dalam pembolehubah semua? Adakah nilai item bagi setiap gelung?
Malah, semasa gelung for, item yang sama disimpan dalam pembolehubah setiap masa, iaitu nilai item bagi gelung terakhir.
Ini adalah soalan yang sering muncul dalam temu bual Go Lebih menarik apabila digabungkan dengan goroutine Lagipun, masih ada masalah seperti keluaran yang tidak sesuai.
Jika anda ingin menyelesaikan masalah ini, anda perlu menulis semula atur cara seperti berikut:
var all []*Itemfor _, item := range items { item := item all = append(all, &item) }
Untuk mengisytiharkan semula pembolehubah item, simpan pembolehubah item bagi gelung for dan kemudian tambahkannya.
Kes 2: Fungsi penutupan
Berikut ialah kod kes kedua:
var prints []func()for _, v := range []int{1, 2, 3} { prints = append(prints, func() { fmt.Println(v) }) }for _, print := range prints { print() }
Ini Apa adakah keluaran program segmen? Tanpa aksara & alamat, adakah ia mengeluarkan 1, 2, 3?
Hasil keluaran ialah 3, 3, 3. kenapa ni?
Salah satu perkara utama masalah ialah fungsi penutupan Malah, semua penutupan mencetak v. Outputnya ialah 3 kerana selepas gelung for tamat, nilai akhir v ditetapkan kepada 3, dan itu sahaja.
Jika anda ingin mencapai kesan yang diingini, anda masih perlu menggunakan penugasan semula universal. Kod yang ditulis semula adalah seperti berikut:
for _, v := range []int{1, 2, 3} { v := v prints = append(prints, func() { fmt.Println(v) }) }
Tambah pernyataan v := v
, dan hasil keluaran program ialah 1, 2, 3.
Berhati-hati melihat projek Go yang telah anda tulis Adakah semuanya biasa kepada anda? Dengan kaedah transformasi ini, kami menang.
Terutama dengan kaedah penulisan Goroutine, ramai pelajar akan lebih cenderung untuk terbalik di sini.
Penyelesaian
Betulkan idea
Malah, pasukan teras Go telah pun secara dalaman dan dalam komuniti Selepas berbincang untuk masa yang lama, saya berharap untuk mentakrifkan semula sintaks bagi gelung. Perkara yang anda ingin capai ialah: jadikan pembolehubah gelung setiap lelaran dan bukannya setiap kali melalui gelung .
Penyelesaiannya ialah menambah penugasan semula tersirat pada permulaan setiap pembolehubah lelaran x pada permulaan setiap badan gelung, iaitu, x := x
, yang boleh menyelesaikan atur cara di atas. lubang tersembunyi. Ia sama seperti yang kami lakukan sekarang, kecuali kami menambahkannya secara manual Perkara yang dilakukan oleh pasukan Go ialah mengendalikannya secara tersirat dalam pengkompil.
Biarkan pengguna membuat keputusan sendiri
Apa yang lebih memalukan ialah pasukan Go melarang mentakrifkan semula bahasa dalam peralihan Cadangan: Go 2, jadi rsc tidak boleh langsung Lakukan ini.
Oleh itu, terpulang kepada pengguna untuk mengawal "pecah" ini dengan menukar semantik berdasarkan baris go dalam setiap fail go.mod pakej.
Jika kita menukar gelung for yang dibincangkan dalam artikel ini kepada lelaran dalam Go1.30, maka pengisytiharan versi go dalam fail go.mod akan menjadi kunci.
Seperti yang ditunjukkan di bawah:
Go 1.30 atau lebih tinggi akan melelaran pembolehubah setiap kali, manakala versi Go yang lebih awal akan menggelungkan pembolehubah setiap kali.
Dengan cara ini, masalah gelung for yang dinyatakan di atas akan dapat diselesaikan pada tahap tertentu.
Ringkasan
Masalah pembolehubah dalam gelung for sentiasa menjadi topik kegemaran pemeriksa utama Go. Selain itu, ia sememangnya dihadapi dalam pengaturcaraan sebenar Go kod.
Walaupun rsc berharap untuk merintis fail go.mod dan menggunakan pengisytiharan versi go untuk mengubah suai semantik (penambahan dan pemadaman tidak dibenarkan). Ini sudah pasti membuka pintu belakang kepada jaminan keserasian Go1.
Jika dilaksanakan, perubahan ini akan menghasilkan semantik yang berbeza antara versi Go sebelumnya dan yang lebih baru. Mungkin juga menjadi suis semantik dalam fail go.mod.
Ini jelas merupakan soalan yang sangat sukar.
Atas ialah kandungan terperinci Betapa menyedihkan gelung for dalam bahasa Go?. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!