- Bản phát hành này tập trung vào generic method, cải thiện struct literal và suy luận kiểu, đồng thời bổ sung các tính năng thực dụng trên toàn bộ thư viện chuẩn, runtime và toolchain
- Cấp phát bộ nhớ chuyên biệt theo kích thước giúp giảm chi phí của một số lần cấp phát dưới 80 byte tới 30%; với các chương trình nặng về cấp phát, dự kiến hiệu năng tăng khoảng 1% và binary tăng khoảng 60KB
encoding/json/v2được cung cấp chính thức vàencoding/jsonhiện có cũng dùng v2 ở bên trong; bổ sung gói UUID chuẩn và chữ ký ML-DSA dựa trên FIPS 204- Hồ sơ
goroutineleak, nhãn pprof trong traceback,synctest.Sleepcho thời gian ảo, máy chủ kiểm thử HTTP trong bộ nhớ giúp chẩn đoán và kiểm thử đồng thời dễ hơn - Việc kênh timer không còn buffer, tự động đọc hết body phản hồi HTTP, và siết chặt hạn chế
//go:linknamecó thể ảnh hưởng tới mã hiện có, nên cần kiểm tra tương thích trước khi chuyển sang Go 1.27
Ngôn ngữ và hệ thống kiểu
- Trọng tâm của Go 1.27 là generic method, cho phép khai báo tham số kiểu riêng độc lập với receiver
- Trước đây chỉ hàm cấp cao nhất mới có thể là generic, nên cả các phép toán thuộc về một kiểu cũng phải viết dưới dạng hàm của package
- Có thể định nghĩa dưới dạng method các phép toán trả về kiểu phần tử khác với đầu vào, như
Box[T].Map[U] - Interface vẫn không thể khai báo method có tham số kiểu, và cũng không thể hiện thực interface bằng generic method
- Với khóa trong struct literal, ngoài tên field cấp cao nhất, có thể dùng cả selector field hợp lệ
- Có thể khởi tạo trực tiếp field được promoted từ embedded struct, như
User{ID: 7}
- Có thể khởi tạo trực tiếp field được promoted từ embedded struct, như
- Suy luận kiểu hàm được mở rộng tới cả conversion và composite literal
- Suy luận đối số kiểu của hàm generic dựa trên kiểu hàm được kỳ vọng, như
[]func([]int) int{first, last} - Trước đây phải tự instantiate như
first[int],last[int]
- Suy luận đối số kiểu của hàm generic dựa trên kiểu hàm được kỳ vọng, như
Runtime và hiệu năng
- Compiler gọi routine cấp phát chuyên biệt theo kích thước, giảm chi phí một số lần cấp phát bộ nhớ dưới 80 byte tới 30%
- Mức cải thiện hiệu năng tổng thể trong các chương trình thực tế nặng về cấp phát dự kiến khoảng 1%
- Không cần sửa mã, nhưng binary tăng khoảng 60KB bất kể workload
- Có thể tắt bằng
GOEXPERIMENT=nosizespecializedmalloc, nhưng tùy chọn này dự kiến bị loại bỏ trong Go 1.28
- Bổ sung ba tối ưu hóa compiler được bật mặc định
- known bits data-flow pass theo dõi các bit chắc chắn là 0 hoặc 1 trong giá trị để loại bỏ phép toán dư thừa
- Di chuyển mã bất biến vòng lặp, đưa các tính toán không đổi trong quá trình lặp ra ngoài vòng lặp
- Biên dịch
switchthỏa điều kiện thành bảng tra cứu, bao gồm cảfallthrough
GOEXPERIMENT=mapsplitgroupthử nghiệm đổi bố cục bộ nhớ của nhóm map từKVKVKVKVsangKKKKVVVV; mặc định đang tắt- Linker chuyển type descriptor và itab sang section
.go.typechuyên biệt, đồng thời loại bỏtypelinksvàitablinks- Vì
reflect.typelinkstrả về kiểu thay vì offset, các thư viện truy cập symbol này bằng//go:linknamecó thể bị ảnh hưởng
- Vì
Chẩn đoán goroutine và profiling
- Các module có
go.modlà Go 1.27 trở lên sẽ hiển thị nhãnruntime/pproftrong header goroutine của traceback- Ngữ cảnh gắn bằng
pprof.Do, như{request: 42}, sẽ xuất hiện trong crash dump,SIGQUIT, và đầu raruntime.Stack - Vẫn có thể dùng
GODEBUG=tracebacklabels=0để tránh lộ nhãn nhạy cảm trong traceback
- Ngữ cảnh gắn bằng
- Trình phát hiện rò rỉ goroutine, vốn là tính năng thử nghiệm của Go 1.26, được nâng lên thành profile chính thức
goroutineleak- Chạy GC để tìm các goroutine vĩnh viễn không thể tiếp tục, chẳng hạn đang kẹt ở channel hoặc mutex, rồi in stack
- Trong service có thể thu thập qua endpoint
/debug/pprof/goroutineleakvà không cầnGOEXPERIMENT
Mã hóa và định danh
- Gói crypto/mldsa mới hiện thực chữ ký hậu lượng tử ML-DSA của FIPS 204
- Ba bộ tham số
MLDSA44,MLDSA65,MLDSA87đánh đổi giữa kích thước khóa/chữ ký và mức bảo mật - ML-DSA cũng được bổ sung vào khóa/chữ ký của
crypto/x509và cơ chế chữ ký TLS 1.3 củacrypto/tls
- Ba bộ tham số
- Gói uuid mới trong thư viện chuẩn tạo và parse UUID RFC 9562 bằng số ngẫu nhiên an toàn về mặt mật mã
uuid.New()chọn phương thức phù hợp cho mục đích thông thường;NewV4()tạo UUID thuần ngẫu nhiên,NewV7()tạo UUID theo thứ tự thời gian tạo- UUID cấu thành từ số ngẫu nhiên có thể so sánh được, nên có thể dùng trực tiếp
== - UUID v7 sắp xếp theo thời gian phù hợp làm khóa cơ sở dữ liệu
JSON và API xử lý dữ liệu
- encoding/json/v2 và
encoding/json/jsontextcấp thấp được cung cấp mà không cầnGOEXPERIMENT=jsonv2encoding/jsonv1 hiện có cũng dùng implementation v2 ở bên trong- Ngoài một số nội dung thông báo lỗi, hành vi hiện có được giữ nguyên nên không cần migration
- Nếu có vấn đề tương thích, có thể khôi phục implementation v1 gốc bằng
GOEXPERIMENT=nojsonv2 - Vì v2 mặc định không sắp xếp khóa map để tăng hiệu năng, các test cần đầu ra ổn định phải chỉ định
json.Deterministic
strings.CutLastvàbytes.CutLasttách giá trị theo dấu phân tách cuối cùng- Nếu không có dấu phân tách, trả về toàn bộ input, phần sau rỗng, và
false
- Nếu không có dấu phân tách, trả về toàn bộ input, phần sau rỗng, và
Hasher[T]generic củahash/maphashđịnh nghĩa đồng thời chiến lược hash và so sánh bằng nhau của giá trị- Các giá trị bằng nhau bắt buộc phải có cùng hash
- Có
ComparableHasher[T]cho các kiểu có thể so sánh, và cũng có thể hiện thực chiến lược tùy chỉnh như chuỗi không phân biệt hoa thường
math/big.Int.Dividetính đồng thời thương và số dư, đồng thời áp dụng cách làm tròn tường minh trongTrunc,Floor,Round,Ceil- Số dư cũng thay đổi theo cách làm tròn, bù đắp hạn chế cắt về 0 của
QuovàModhiện có trong mã tài chính/số học
- Số dư cũng thay đổi theo cách làm tròn, bù đắp hạn chế cắt về 0 của
math/rand/v2.(*Rand).Ntạo số ngẫu nhiên bị giới hạn phạm vi cho số nguyên hoặc kiểu duration từ nguồn*Randriêng
SIMD di động
- Gói simd thử nghiệm cung cấp API SIMD độc lập với kích thước vector, bật bằng
GOEXPERIMENT=simd- Ở môi trường được hỗ trợ, nó biên dịch thành lệnh vector phần cứng thực tế; nếu không, thay bằng mô phỏng Go thuần
- Số lane của các kiểu như
Float32skhông cố định mà theo độ rộng phần cứng của từng máy
- Thư viện chuẩn đã dùng intrinsic
simd/archsimdnội bộMemHash32,MemHash64,StrHashcủa map Swiss Table được hiện thực lại trên nền SIMD mới
Kiểm thử quyết định luận
testing/synctest.Sleepvừa tiến thời gian ảo vừa chờ đến khi mọi goroutine ổn định- Trong bong bóng
synctest, thời gian thực không trôi qua nên cả chờ 2 giây cũng hoàn tất ngay - Thay thế mã lặp lại dùng kết hợp
time.Sleepvàsynctest.Waithiện có
- Trong bong bóng
httptest.NewTestServerchạy server bằng mạng ảo trong bộ nhớ thay vì cổng TCP thậtsrv.Client()kết nối trực tiếp tới handler qua pipe nội bộ trong process- Được dọn tự động bằng
t.Cleanup, nên không cầndefer srv.Close() - Khi kết hợp với
testing/synctest, cả vòng khứ hồi HTTP cũng có thể được kiểm thử nhanh và quyết định luận trong thời gian ảo
Thay đổi về mạng và tương thích
- Các channel do
time.After,time.NewTimer,time.NewTickerv.v. trả về luôn là channel đồng bộ không buffer- Thiết lập GODEBUG
asynctimerchantừng khôi phục hành vi có buffer trước đây đã bị loại bỏ
- Thiết lập GODEBUG
- Trong HTTP/1,
http.Response.Body.Closeđọc phần body chưa đọc tới một giới hạn thận trọng để hỗ trợ tái sử dụng kết nối- Nếu từng dựa vào
Closeđể dừng sớm một lượt tải lớn, cần tắt tái sử dụng bằngTransport.DisableKeepAlives
- Nếu từng dựa vào
- Server HTTP/2 hiểu priority của client theo RFC 9218 và xử lý các stream ưu tiên cao trước
- Có thể khôi phục hành vi round-robin cũ bằng
Server.DisableClientPriority = true
- Có thể khôi phục hành vi round-robin cũ bằng
crypto/x509.SystemCertPooltrên Windows và macOS hỗ trợSSL_CERT_FILEvàSSL_CERT_DIR- Khi biến được đặt, nó đọc chứng chỉ gốc trên đĩa và dùng trình xác minh của Go thay vì API nền tảng
- Có thể tắt bằng
GODEBUG=x509sslcertoverrideplatform=0
- Implementation HTTP/2 trước đây nằm trong file generated
h2_bundle.godài 12.226 dòng được thay bằng packagenet/http/internal/http2thật net/httpđược bổ sung hook HTTP/3 có thể cắm được, ở giai đoạn trước khi công khai ra bên ngoài, và một phần bộ test chạy trên HTTP/3- Chưa có public API có thể gọi, nhưng đã có nền tảng cho
http.Transportdựa trên QUIC trong tương lai
- Chưa có public API có thể gọi, nhưng đã có nền tảng cho
Toolchain
go testmặc định chạy kiểm tra vetstdversionđể phát hiện việc dùng symbol thư viện chuẩn mới hơn phiên bản Go khai báo tronggo.mod- Có thể xem tài liệu của một phiên bản module cụ thể bằng
go doc pkg@version go doc -exliệt kê các ví dụ có thể chạy; nếu chỉ định trực tiếp tên ví dụ, nó sẽ in sourcego fixbổ sung các analyzer hiện đại hóaatomictypes,embedlit,slicesbackward,unsafefuncswaitgroupđược đổi tên thànhwaitgroupgo, cònfmtappendfbị loại bỏ
- Trong module Go 1.27 trở lên,
go mod tidygộp các khốirequirerải rác thành hai khối cho dependency trực tiếp/gián tiếp, đồng thời giữ comment go tool trace -http=:6060chỉ bind vào localhost nếu chỉ cung cấp port; để truy cập từ bên ngoài cần chỉ định địa chỉ- Lệnh
goloại bỏ hỗ trợ hệ thống quản lý phiên bản Bazaar (bzr) compile,link,asm,cgo,cover,packhỗ trợ response file (@file) theo kiểu GCC để tránh giới hạn độ dài dòng lệnh
Unicode và ranh giới bảo mật
- Dữ liệu Unicode của thư viện chuẩn được cập nhật từ Unicode 15 lên Unicode 17
- Các ký tự được bổ sung trong Unicode 16 cũng được phân loại đúng là ký tự symbol/printable
- Đã sửa vấn đề có thể thoát ra ngoài root bằng
os.Root.ReadDirvàReaddir - Việc dùng
//go:linknamekhông được phê duyệt trở nên khó hơn- Chỉ thị
linknamestdđánh dấu các linkname chỉ thư viện chuẩn mới có thể import - Vì linker cũng kiểm tra truy cập linkname tới symbol assembly, các mã phụ thuộc vào symbol nội bộ không chính thức cần kiểm thử sớm
- Chỉ thị
1 bình luận
Ý kiến trên Lobste.rs
Có lẽ đây là bản phát hành tốt nhất từ trước đến nay. SIMD, uuid, jsonv2 cuối cùng cũng đã có
Hơi lạc đề một chút, nhưng đây là ví dụ điển hình về việc lỗi phát sinh khi coi mọi thứ đều là chuỗi và không xem xét các ràng buộc cũng như mối liên hệ giữa các phương thức của interface
Equalbỏ qua phân biệt hoa thường, nhưngHashdùng giá trị đã chuyển thành chữ thường. Tuy nhiênEqualFoldvàToLowerkhông định nghĩa cùng một quan hệ tương đươnghttps://github.com/golang/go/issues/52204
"\u017F"(ſ, chữ s dài) và"s"là như nhau theoEqualFold, nhưng kết quả sau khiToLowertừng cái lại khác nhau. Vì vậy nếu chèn"s"rồi chèn"ſ"thì hash sẽ khác và bị thêm thành mục riêngĐiều thú vị hơn là tài liệu ngay tại đó cũng cảnh báo đúng trường hợp này
https://github.com/golang/go/…
https://github.com/golang/go/…
Mừng vì có người khác tiếp tục từ chỗ Anton dừng lại
Tôi thích Go, nhưng cứ tiếp tục thêm các tính năng kiểu này qua mỗi bản phát hành khiến tôi nghi ngờ liệu cú pháp Go có đủ thanh lịch hay không
func (b Box[T]) Map[U any](f func(T) U) Box[U] {Ngược lại, sự dài dòng của Go và Zig lại hay ở chỗ không cần cuộn sang nơi khác để tìm định nghĩa receiver. Ở vị trí gọi hàm — nơi có thể còn quan trọng hơn phần định nghĩa — mọi thứ trông gần như giống nhau và cũng không cần ghi rõ kiểu
Tôi đã rời Go một thời gian, nên jsonv2 khá đáng mong đợi. Tuy vậy, nếu nó trở thành mặc định thì có phải Go sẽ phá vỡ cam kết tương thích lâu nay không
encoding/json/v2, nên phải tự chọn dùng.encoding/jsonhiện có dùng v2 ở bên trong nhưng vẫn đảm bảo hành vi cũ, và jsonv2 cũng có cờ để tái hiện các hành vi ngoại lệ của v1, nên không phá vỡ cam kết tương thích