Rilis Go 1.22
(go.dev)- Variabel loop
forkini dibuat baru pada setiap iterasi untuk menghindari bug berbagi yang tidak disengaja, danrangepada bilangan bulat juga kini dimungkinkan - Kompatibilitas tetap mengikuti janji kompatibilitas Go 1, dan hampir semua program Go diharapkan tetap dapat dikompilasi dan dijalankan seperti sebelumnya
- Di workspace, direktori vendor yang dibuat dengan
go work vendordapat digunakan; jika adavendordi workspace,-mod=vendormenjadi nilai default - Dukungan
go getdi luar modul pada mode legacyGOPATHdenganGO111MODULE=offdihentikan; perintah build lain sepertigo builddango testtetap berfungsi untuk program legacyGOPATH - Runtime kini menempatkan metadata GC berbasis tipe di dekat objek heap, meningkatkan performa CPU program Go sebesar 1–3% dan mengurangi overhead memori banyak program sekitar 1%
- Penyelarasan alamat sebagian objek dapat berubah dari sebelumnya 16 byte atau lebih menjadi penyelarasan 8 byte; kode assembly yang mengasumsikan penyelarasan lebih tinggi perlu diperbaiki, dan
GOEXPERIMENT=noallocheadersdapat digunakan sebagai solusi sementara - Build PGO dapat melakukan devirtualization pada lebih banyak pemanggilan, dan saat PGO diaktifkan pada sekumpulan program Go representatif, performa runtime meningkat 2–14%
- Paket
v2pertama di standard library,math/rand/v2, ditambahkan; menyediakanReadyang tidak diwariskan, generator global yang selalu diberi seed acak, sumberChaCha8danPCG, serta fungsi generikN - Pola routing
net/http.ServeMuxmendukung metode dan wildcard; ada sedikit perubahan yang memutus kompatibilitas mundur pada pola yang berisi{}dan pemrosesan path yang di-escape, dan perilaku lama dapat dipulihkan denganGODEBUG=httpmuxgo121=1 - Versi minimum default server
crypto/tlsberubah menjadi TLS 1.2 jika tidak ditentukan, dan cipher suite tanpa ECDHE tidak lagi disediakan secara default pada handshake sebelum TLS 1.3 - Execution tracer dirombak besar-besaran: kini menggunakan jam OS di sebagian besar platform, menyediakan trace tersegmentasi yang dapat diproses secara streaming, durasi syscall penuh, serta informasi OS thread tempat goroutine berjalan
- UI web alat
tracediperbarui sebagai bagian dari dukungan tracer baru, dan pada trace dari program yang dibangun dengan Go 1.22 atau lebih baru mendukung tampilan berorientasi thread serta penampilan durasi syscall penuh vetmenyesuaikan peringatan loop closure agar sesuai dengan semantik variabel loop Go 1.22, serta menambahkan peringatan untukappendtanpa nilai,time.Sinceyang tidak ditunda di dalamdefer, dan ketidakcocokan key/valuelog/slog- Bootstrap memerlukan setidaknya point release final Go 1.20; Go 1.24 diperkirakan akan mensyaratkan setidaknya point release final Go 1.22
- Pada
darwin/amd64, Go toolchain kini secara default menghasilkan PIE; Go 1.22 adalah rilis terakhir yang berjalan di macOS 10.15 Catalina, dan Go 1.23 memerlukan macOS 11 Big Sur atau lebih baru - Tipe
Aliasdan fungsiUnaliasditambahkan kego/types; padagotypesalias=1, klien harus menangani tipeAlias slices.Delete,DeleteFunc,Compact,CompactFunc,Replacemelakukan zeroing pada elemen di rentang yang diperkecil, danInsertselalu memicu panic jikaiberada di luar rentang- Fungsi pembacaan direktori Windows membaca entri secara batch untuk mengurangi jumlah system call, dengan peningkatan performa hingga 30%
1 komentar
Pendapat di Hacker News
Selama 3 tahun terakhir terutama memakai TypeScript, lalu belakangan mulai memakai Go; awalnya agak khawatir karena kurangnya fungsi array atau sistem tipe yang kurang fleksibel
Namun ketika mencoba menyiapkan ulang proyek TypeScript untuk tim berukuran 4–5 orang, terlalu banyak waktu habis untuk linting, memilih library routing server, memilih server, standar coding, penanganan error dasar, memaksakan error kustom atau tipe
Resultagar terhindar dari nerakatry/catchbertingkat, testing dan mocking, konfigurasi Prisma, dan sebagainyaSaya memang suka TypeScript, tetapi memakai bahasa dengan standard library yang hebat, type safety yang benar, dan standar coding bawaan itu benar-benar nyaman. Go juga punya quirks, tetapi cukup bagus, dan routing yang kini masuk standard library berarti ada satu hal lagi yang tidak perlu dipikirkan, jadi menyenangkan. Sekarang tinggal menunggu fungsi
map/filter/finduntuk sliceDi setiap rilis, TypeScript makin kompleks demi power user, sedangkan Go memasukkan hal-hal yang sebelumnya kurang, seperti
rangeuntuk integer, sehingga lebih sederhana dipakaiIni mirip sekuel gim yang terus menambah latar dan mekanik sampai akhirnya perlu reset demi pengguna baru; bahasa pemrograman sulit melakukan itu, jadi bagus bahwa Go menyadarinya
go:embeddango:generateselalu mengesankan setiap kali saya melihatnya di proyek lainPaket
golang.org/xjuga bagus karena implementasi untuk hampir semua RFC internet sudah siap pakaimap/filter/finduntuk slice hadir, bisa memakai library lo yang terinspirasi lodashIni alat serbaguna favorit saya di proyek Go: https://github.com/samber/lo
Polanya berulang: saat membaca dokumentasi untuk melakukan sesuatu, tak lama kemudian seseorang memberi tahu trik yang bisa dipakai tetapi tidak ada di dokumentasi
Kalau catatan rilis resminya terasa agak kaku, saya sudah membuat versi interaktif: https://antonz.org/go-1-22
forloop yang dibagi bersama awalnya tidak langsung saya pahami, tetapi melihat hasil yang tidak terduga dengan menjalankannya sendiri membantuCompactdanReplacemembingungkan; saya tidak yakin apakah itu benarSaya memakai Go selama lebih dari 9 tahun, dan 4 tahun terakhir banyak memakai Dart karena Flutter; menurut saya kedua bahasa ini punya sikap terhadap kompleksitas yang benar-benar berlawanan. Dart ingin menambahkan semua fitur yang mungkin, sedangkan Go sebaliknya
Pertama, di Dart ada terlalu banyak cara untuk menginisialisasi nilai di dalam class, sehingga banyak waktu terpakai. Bergantung pada prefiks
final/const/static/late, lokasi inisialisasi bisa berbeda-beda: constructor, factory,initState()milik FlutterStatefulWidget, dan sebagainya; saat refactoring, inisialisasi harus banyak diubah. Getter yang membuat fungsi tampak seperti variabel juga menambah kebingungan di codebase baruKedua, Dart punya banyak fitur yang cocok dijejalkan dalam satu baris, seperti map dan stream, sehingga kita tergoda cepat membuat kode satu baris yang sulit dipahami. Namun saat debugging, atau ketika developer junior bertemu hack seperti
firstWhereOrNulldan parameter opsional sepertiorElse: () => null, mereka menjadi sangat bingung. Null safety atau error tipe yang rumit juga sering membuat pekerjaan terhenti, dan ketika mengubahnya menjadi loopforsederhana ala Go, rasanya benar-benar legainitStateuntuk hal yang tidak langsung terkait UI. Misalnya, kalau bukan sekadar mengatur hint field teks, saya cenderung menghindarinyaSebagian besar halaman Flutter punya sangat sedikit pekerjaan, atau parent membuat objek
MyPageController, menginisialisasinya sesuai kebutuhan, lalu child page berjalan mengikuti controller itu. Misalnya, di halaman daftar, ketika pengguna ingin mengedit item, parent membuat controller, memasukkan item ke dalamnya, lalu mengirimnya ke child page; setelah kembali, parent bisa melihat item, variabel, atau callback di controller untuk menentukan perubahan UIDengan cara ini, interaksi antar-widget bisa dikontrol secara rinci tanpa menyentuh hal seperti
InheritedWidget. Tentu lebih baik dipakai bersama library state management, tetapi dalam praktiknya sering juga tidak dipakairangejuga demikian; pada akhirnya jumlah karakter yang diketik mirip dengan comprehension sepertiforEach(f), hanya saja tersebar menjadi tiga baris sehingga tampak lebih panjang, dan kalau ditulis eksplisit sebenarnya bukan hal besarNamun terkait inisialisasi, saya berharap Go punya cara idiomatis untuk menginisialisasi field struct dengan nilai tertentu. Tidak adanya constructor tidak masalah, tetapi kadang saya ingin
boolsecara default diinisialisasi sebagaitrueinitStateadalah override dariStatefulWidgetdan tidak berbeda dari event lifecycle di framework lain; itu konsep di sisi Flutter, jadi bukan sesuatu yang sifatnya membingungkan dengan constructorMemang bisa membingungkan harus memakai constructor biasa atau factory, tetapi sulit mengatakan Go lebih unggul karena
initStateSaat
io.Copymenyalin dariTCPConnkeUnixConn, jika memungkinkan ia akan memakai system callsplice(2)di Linux, dan menggunakan metode baruTCPConn.WriteToDengan upgrade interface ini, zero-copy I/O kembali bertambah secara transparan. Efek yang diperoleh dari pola ini di paket
iobenar-benar besarMeski begitu, masih dalam batas yang bisa diharapkan
Pola routing yang ditingkatkan adalah perbaikan yang bagus, terutama saat masa depan Gorilla Mux sedang tidak pasti
Namun perubahan ini memecah kompatibilitas mundur dalam beberapa cara kecil: ada bagian yang jelas seperti perubahan perilaku pola yang berisi
{dan}, serta bagian yang kurang jelas seperti penanganan path yang di-escape. Ini dikendalikan lewat fieldhttpmuxgo121padaGODEBUG; dengan mengaturhttpmuxgo121=1, perilaku lama bisa dipulihkanNamun saya penasaran mengapa ini tidak bertentangan dengan janji kompatibilitas Go 1 bahwa “program yang ditulis sesuai spesifikasi Go 1 akan terus dikompilasi dan berjalan dengan benar tanpa perubahan selama masa berlaku spesifikasi tersebut”
godigo.modJika 1.22 atau lebih baru, Anda mendapat perilaku library baru; jika tidak, Anda mendapat perilaku lama. Seberapa baik ini bekerja dalam praktik masih perlu dilihat
{dan}pada path HTTP handler hampir tidak adaMereka juga menyediakan cara untuk mematikan perilaku baru, jadi tidak memaksa perubahan kode, meski tetap harus mengatur environment variable baru
Perubahan semantik loop
forpada rilis ini juga contoh serupa; pada dasarnya itu perubahan yang memecahkan kompatibilitas. Meski begitu, semua program Go tetap dikompilasi dan berjalan, hanya sebagian perilakunya sedikit berubah. Menurut saya Go memilih pendekatan pragmatis, dan itu salah satu alasan keberhasilannyago.mod, setidaknya seharusnya pecahkan dengan cara yang lebih baikDaripada harus mencari isu runtime yang halus ketika mengubah
go.modke 1.22, jauh lebih baik jika kodenya gagal dikompilasi sajaDi Go 1.22, setiap iterasi loop akan membuat variabel baru
Hal ini juga pernah dibahas di sini sebelumnya: https://news.ycombinator.com/item?id=33160236 - Go: Redefining For Loop Variable Semantics (2022)
Mungkin terdengar kuno, tapi saya tidak suka penambahan
rangeuntuk fungsi. Kenyamanannya tidak cukup besar untuk membenarkan kompleksitas tambahan pada bahasa, dan gaya fungsional terasa tidak selaras dengan gaya Go yang eksplisit, imperatif, verbose, tetapi fiturnya sedikit. Menurut saya itu salah satu keunggulan besar GoDengan alasan yang sama, saya juga merasa
rangeuntuk integer adalah arah yang keliru. Kumpulan fitur Go yang tipis dan beban kognitifnya yang rendah selalu menjadi kekuatan utama sekaligus pembedaSalah satu masalah besar dalam pengembangan software adalah mencegah developer menambahkan kompleksitas atau memamerkan kemampuan. Terutama developer di awal karier cenderung membuat solusi terlalu kompleks, alih-alih menyelesaikan masalah secara langsung meski kurang elegan dan lebih panjang
Dukungan generics Go saat ini belum cukup canggih untuk menopangnya, sehingga muncul batasan-batasan yang terasa dipaksakan secara aneh
Penambahan
sql.Null[T]bagus. Di proyek baru saya mungkin akan mulai memakainyaDi pekerjaan saat ini, saya bergantung pada null [0] dari sqlboiler yang API-nya sangat mirip. Ia berperilaku seperti
sql.Null, tetapi punya metode tambahanIsSet() boolyang memberi tahu apakah nilainya pernah di-set secara eksplisit, sehingga membantu membedakan “null yang disengaja” dan “null karena belum diinisialisasi”. Kelihatannya bagus, tetapi dalam praktiknya saya belum pernah menggunakannyaSaya menantikan untuk melihat lagi mux standard library dan apakah mungkin menghapus chi. Senang sekali fitur seperti ini masuk ke standard library
Jika fitur seperti ini masuk standard library, ia akan selalu dipelihara dan memastikan banyak program Go memakai pendekatan yang sama
Saya penasaran, kalau memakai Go di production, apakah bisa cepat pindah ke versi terbaru, atau justru terikat pada rilis lama
Dari proyek-proyek publik, terlihat banyak yang menghindari fitur yang relatif baru. Walau tidak memakai generics, saya ingin memakai
anyyang muncul di Go 1.18 alih-alihinterface{}lama, dan saya juga pernah dengar bahwa yang terakhir lebih “idiomatis”Kali ini agak rumit: tim Go merilis 1.22 sebelum kami menaikkan default ke 1.21. Sekarang menunggu sudah hampir menjadi kebiasaan, dan jarang sekali rilis Go memecahkan sesuatu
Misalnya untuk generics, kami menunggu sekitar 6 bulan sebelum benar-benar memakainya, sambil memastikan kegunaannya, developer experience, serta dampaknya terhadap kecepatan build dan test tidak besar
Namun kami juga menyediakan aplikasi end-user dengan Go, dan untuk yang ini kami harus tetap di 1.20 karena kompatibilitas dengan OS klien lama. Karena ada pemangkasan cukup besar di 1.21, kemungkinan kami akan tetap di 1.20 selama beberapa tahun
latestGo, dan test suite kami cukup solid, jadi pada dasarnya update terjadi otomatis. Jika ada yang tidak cocok, pipeline akan rusak, lalu kami memutuskan apakah akan mengunci ke versi terakhir yang berfungsi atau menunda update sampai perubahan yang memecahkan itu diperbaikiSekali dalam beberapa tahun, kadang bug edge case yang halus antara versi baru dan package pihak ketiga muncul, tetapi bug seperti itu, menurut definisinya, lolos dari test suite, jadi kemungkinan besar tidak akan tertangkap meski upgrade dilakukan manual
Jika khawatir soal dukungan compiler Go lama, Anda bisa menaruh build condition untuk versi lama dan mendefinisikan hal yang hilang. Misalnya, di bawah
// +build !go1.7Anda bisa menaruhtype any = interface{}