Ghi chú phát hành Go 1.21

Giới thiệu Go 1.21

Bản phát hành Go mới nhất, phiên bản 1.21, ra mắt sáu tháng sau Go 1.20. Phần lớn thay đổi nằm ở phần triển khai của toolchain, runtime và thư viện. Như mọi khi, bản phát hành duy trì cam kết tương thích của Go 1; thực tế, Go 1.21 cải thiện cam kết đó. Chúng tôi kỳ vọng hầu như tất cả chương trình Go vẫn tiếp tục biên dịch và chạy như trước.

Go 1.21 giới thiệu một thay đổi nhỏ về cách đánh số bản phát hành. Trước đây, chúng tôi dùng Go 1.N để chỉ cả phiên bản ngôn ngữ Go tổng thể và họ phát hành cũng như bản phát hành đầu tiên trong họ đó. Bắt đầu từ Go 1.21, bản phát hành đầu tiên giờ là Go 1.N.0. Hôm nay chúng tôi phát hành cả ngôn ngữ Go 1.21 và triển khai ban đầu của nó, bản phát hành Go 1.21.0. Các ghi chú này đề cập đến “Go 1.21”; các công cụ như go version sẽ báo cáo “go1.21.0” (cho đến khi bạn nâng cấp lên Go 1.21.1). Xem “Phiên bản Go” trong tài liệu “Go Toolchains” để biết chi tiết về cách đánh số phiên bản mới.

Thay đổi ngôn ngữ

Go 1.21 thêm ba hàm built-in mới vào ngôn ngữ.

  • Các hàm mới minmax tính giá trị nhỏ nhất (hoặc lớn nhất, với max) trong một số lượng cố định các đối số đã cho. Xem đặc tả ngôn ngữ để biết chi tiết.
  • Hàm mới clear xóa tất cả phần tử khỏi một map hoặc đặt tất cả phần tử của một slice về zero. Xem đặc tả ngôn ngữ để biết chi tiết.

Thứ tự khởi tạo gói giờ được định nghĩa chính xác hơn. Thuật toán mới là:

  • Sắp xếp tất cả gói theo đường dẫn import.
  • Lặp lại cho đến khi danh sách gói trống:
    • Tìm gói đầu tiên trong danh sách mà tất cả import của nó đã được khởi tạo.
    • Khởi tạo gói đó và xóa nó khỏi danh sách.

Điều này có thể thay đổi hành vi của một số chương trình dựa trên thứ tự khởi tạo cụ thể không được thể hiện bằng các import tường minh. Hành vi của các chương trình như vậy không được định nghĩa rõ ràng bởi đặc tả trong các bản phát hành trước. Quy tắc mới cung cấp định nghĩa rõ ràng.

Nhiều cải tiến tăng sức mạnh và độ chính xác của suy diễn kiểu đã được thực hiện.

  • Một hàm generic (có thể được khởi tạo một phần) giờ có thể được gọi với các đối số bản thân là các hàm generic (có thể được khởi tạo một phần). Compiler sẽ cố gắng suy diễn các đối số kiểu còn thiếu của callee (như trước) và, cho mỗi đối số là hàm generic không được khởi tạo đầy đủ, các đối số kiểu còn thiếu của nó (mới). Các trường hợp sử dụng điển hình là các lời gọi đến các hàm generic hoạt động trên container (như slices.IndexFunc) nơi một đối số hàm cũng có thể là generic, và nơi đối số kiểu của hàm được gọi và các đối số của nó được suy diễn từ kiểu container. Tổng quát hơn, một hàm generic giờ có thể được dùng mà không cần khởi tạo tường minh khi nó được gán cho một biến hoặc được trả về như một giá trị kết quả nếu các đối số kiểu có thể được suy diễn từ phép gán.
  • Suy diễn kiểu giờ cũng xem xét các phương thức khi một giá trị được gán cho interface: các đối số kiểu cho các tham số kiểu được dùng trong chữ ký phương thức có thể được suy diễn từ các kiểu tham số tương ứng của các phương thức khớp.
  • Tương tự, vì một đối số kiểu phải triển khai tất cả phương thức của ràng buộc tương ứng của nó, các phương thức của đối số kiểu và ràng buộc được khớp, có thể dẫn đến việc suy diễn các đối số kiểu bổ sung.
  • Nếu nhiều đối số hằng số không được gõ thuộc các loại khác nhau (chẳng hạn một int không được gõ và một hằng số dấu phẩy động không được gõ) được truyền cho các tham số có cùng kiểu tham số kiểu (không được chỉ định khác), thay vì lỗi, suy diễn kiểu giờ xác định kiểu bằng cách tiếp cận giống như một toán tử với các toán hạng hằng số không được gõ. Thay đổi này điều chỉnh các kiểu được suy diễn từ các đối số hằng số không được gõ cho phù hợp với các kiểu của biểu thức hằng số.
  • Suy diễn kiểu giờ chính xác khi khớp các kiểu tương ứng trong phép gán: các kiểu thành phần (chẳng hạn các phần tử của slice, hoặc các kiểu tham số trong chữ ký hàm) phải giống hệt nhau (cho các đối số kiểu phù hợp) để khớp, nếu không suy diễn thất bại. Thay đổi này tạo ra thông báo lỗi chính xác hơn: khi trước đây suy diễn kiểu có thể thành công không đúng và dẫn đến phép gán không hợp lệ, compiler giờ báo cáo lỗi suy diễn nếu hai kiểu không thể khớp được.

Tổng quát hơn, mô tả về suy diễn kiểu trong đặc tả ngôn ngữ đã được làm rõ. Tổng hợp lại, tất cả những thay đổi này làm cho suy diễn kiểu mạnh mẽ hơn và các lỗi suy diễn ít bất ngờ hơn.

Go 1.21 bao gồm bản xem trước về một thay đổi ngôn ngữ mà chúng tôi đang xem xét cho phiên bản Go tương lai: biến vòng lặp for thành theo từng lần lặp thay vì theo toàn bộ vòng lặp, để tránh các lỗi chia sẻ vô tình. Để biết chi tiết về cách thử thay đổi ngôn ngữ đó, xem trang wiki LoopvarExperiment.

Go 1.21 giờ định nghĩa rằng nếu một goroutine đang panic và recover được gọi trực tiếp bởi một hàm deferred, giá trị trả về của recover được đảm bảo không phải nil. Để đảm bảo điều này, gọi panic với giá trị interface nil (hoặc nil không được gõ) gây ra runtime panic kiểu *runtime.PanicNilError.

Để hỗ trợ các chương trình được viết cho các phiên bản Go cũ hơn, nil panic có thể được bật lại bằng cách đặt GODEBUG=panicnil=1. Cài đặt này được bật tự động khi biên dịch chương trình mà main package của nó nằm trong module khai báo go 1.20 hoặc cũ hơn.

Công cụ

Go 1.21 thêm hỗ trợ cải thiện cho tương thích ngược và tương thích tiến trong Go toolchain.

Để cải thiện tương thích ngược, Go 1.21 chính thức hóa việc Go sử dụng biến môi trường GODEBUG để kiểm soát hành vi mặc định cho các thay đổi không vi phạm theo chính sách tương thích nhưng dù sao có thể khiến các chương trình hiện tại bị hỏng. (Ví dụ: các chương trình phụ thuộc vào hành vi có lỗi có thể bị hỏng khi lỗi được sửa, nhưng các sửa lỗi không được coi là thay đổi vi phạm.) Khi Go phải thực hiện loại thay đổi hành vi này, nó giờ chọn giữa hành vi cũ và mới dựa trên dòng go trong tệp go.work của workspace hoặc tệp go.mod của main module. Nâng cấp lên Go toolchain mới nhưng để dòng go ở phiên bản Go cũ (cũ hơn) sẽ giữ nguyên hành vi của toolchain cũ. Với hỗ trợ tương thích này, Go toolchain mới nhất luôn nên là triển khai tốt nhất, an toàn nhất của phiên bản Go cũ. Xem “Go, Tương thích ngược, và GODEBUG” để biết chi tiết.

Để cải thiện tương thích tiến, Go 1.21 giờ đọc dòng go trong tệp go.work hoặc go.mod như một yêu cầu tối thiểu nghiêm ngặt: go 1.21.0 có nghĩa là workspace hoặc module không thể dùng với Go 1.20 hoặc Go 1.21rc1. Điều này cho phép các dự án phụ thuộc vào các bản sửa trong các phiên bản Go mới hơn để đảm bảo họ không được dùng với các phiên bản cũ hơn. Nó cũng cho phép báo cáo lỗi tốt hơn cho các dự án sử dụng tính năng Go mới: khi vấn đề là cần phiên bản Go mới hơn, vấn đề đó được báo cáo rõ ràng, thay vì cố build code và in lỗi về import chưa giải quyết hoặc lỗi cú pháp.

Để làm cho các yêu cầu phiên bản nghiêm ngặt hơn mới này dễ quản lý hơn, lệnh go giờ có thể gọi không chỉ toolchain đi kèm trong bản phát hành của nó mà còn các phiên bản Go toolchain khác tìm thấy trong PATH hoặc được tải xuống theo yêu cầu. Nếu dòng go trong go.mod hoặc go.work khai báo yêu cầu tối thiểu về phiên bản Go mới hơn, lệnh go sẽ tìm và chạy phiên bản đó tự động. Directive toolchain mới đặt toolchain tối thiểu được đề xuất để sử dụng, có thể mới hơn tối thiểu go nghiêm ngặt. Xem “Go Toolchains” để biết chi tiết.

Lệnh go

Cờ build -pgo giờ mặc định là -pgo=auto, và hạn chế chỉ định một main package duy nhất trên dòng lệnh đã được bỏ. Nếu tệp có tên default.pgo có mặt trong thư mục của main package, lệnh go sẽ dùng nó để bật tối ưu hóa dựa trên hồ sơ thực thi khi build chương trình tương ứng.

Cờ -C dir giờ phải là cờ đầu tiên trên dòng lệnh khi được dùng.

Tùy chọn go test mới -fullpath in tên đường dẫn đầy đủ trong các thông báo log test, thay vì chỉ tên cơ sở.

Cờ go test -c giờ hỗ trợ ghi test binary cho nhiều gói, mỗi gói vào pkg.test nơi pkg là tên gói. Sẽ là lỗi nếu nhiều hơn một gói test được biên dịch có tên gói đã cho.

Cờ go test -o giờ chấp nhận đối số thư mục, trong đó các test binary được ghi vào thư mục đó thay vì thư mục hiện tại.

Khi dùng external (C) linker với cgo được bật, gói runtime/cgo giờ được cung cấp cho Go linker như một dependency bổ sung để đảm bảo rằng Go runtime tương thích với bất kỳ thư viện bổ sung nào được thêm bởi C linker.

Cgo

Trong các tệp import "C", Go toolchain giờ báo cáo đúng lỗi khi cố khai báo phương thức Go trên kiểu C.

Runtime

Khi in các stack rất sâu, runtime giờ in 50 frame đầu tiên (trong cùng) theo sau bởi 50 frame dưới cùng (ngoài cùng), thay vì chỉ in 100 frame đầu tiên. Điều này giúp dễ dàng hơn để xem cách các stack đệ quy sâu bắt đầu, và đặc biệt có giá trị để debug stack overflow.

Trên các nền tảng Linux hỗ trợ transparent huge pages, Go runtime giờ quản lý rõ ràng hơn những phần nào của heap có thể được hỗ trợ bởi huge pages. Điều này dẫn đến sử dụng bộ nhớ tốt hơn: các heap nhỏ nên thấy ít bộ nhớ được sử dụng hơn (lên đến 50% trong các trường hợp cực đoan) trong khi các heap lớn nên thấy ít huge pages bị phá vỡ hơn cho các phần dày đặc của heap, cải thiện việc sử dụng CPU và độ trễ lên đến 1%. Hệ quả của điều này là runtime không còn cố gắng khắc phục một cài đặt cấu hình Linux cụ thể có vấn đề, điều này có thể dẫn đến chi phí bộ nhớ cao hơn. Cách sửa được khuyến nghị là điều chỉnh cài đặt huge page của OS theo hướng dẫn GC. Tuy nhiên, cũng có các giải pháp thay thế khác. Xem phần về max_ptes_none.

Do điều chỉnh bộ gom rác bên trong runtime, các ứng dụng có thể thấy giảm đến 40% trong độ trễ đuôi ứng dụng và giảm nhỏ trong việc sử dụng bộ nhớ. Một số ứng dụng cũng có thể thấy giảm nhỏ trong throughput. Giảm sử dụng bộ nhớ nên tỷ lệ với sự giảm throughput, sao cho đánh đổi throughput/bộ nhớ của bản phát hành trước có thể được khôi phục (với ít thay đổi về độ trễ) bằng cách tăng GOGC và/hoặc GOMEMLIMIT một chút.

Các lời gọi từ C sang Go trên các thread được tạo trong C yêu cầu một số thiết lập để chuẩn bị cho thực thi Go. Trên các nền tảng Unix, thiết lập này giờ được giữ nguyên qua nhiều lời gọi từ cùng một thread. Điều này giảm đáng kể chi phí của các lời gọi C sang Go tiếp theo từ khoảng 1-3 microsecond mỗi lời gọi xuống còn khoảng 100-200 nanosecond mỗi lời gọi.

Compiler

Tối ưu hóa dựa trên hồ sơ thực thi (PGO), được thêm như bản xem trước trong Go 1.20, giờ sẵn sàng để sử dụng chung. PGO bật các tối ưu hóa bổ sung trên code được xác định là nóng bởi hồ sơ của các workload sản xuất. Như đã đề cập trong phần lệnh Go, PGO được bật theo mặc định cho các binary chứa hồ sơ default.pgo trong thư mục main package. Cải thiện hiệu năng thay đổi tùy theo hành vi ứng dụng, với hầu hết các chương trình từ một tập đại diện các chương trình Go thấy từ 2 đến 7% cải thiện khi bật PGO. Xem hướng dẫn sử dụng PGO để biết tài liệu chi tiết.

Các build PGO giờ có thể devirtualize một số lời gọi phương thức interface, thêm lời gọi cụ thể đến callee phổ biến nhất. Điều này bật tối ưu hóa thêm, chẳng hạn như inline callee.

Go 1.21 cải thiện tốc độ build lên đến 6%, chủ yếu nhờ vào việc build compiler với PGO.

Assembler

Trên amd64, các hàm assembly frameless nosplit không còn tự động được đánh dấu là NOFRAME. Thay vào đó, thuộc tính NOFRAME phải được chỉ định tường minh nếu muốn, vốn đã là hành vi trên các kiến trúc khác hỗ trợ frame pointer. Với điều này, runtime giờ duy trì các frame pointer cho quá trình chuyển đổi stack.

Trình xác minh kiểm tra việc sử dụng sai R15 khi dynamic linking trên amd64 đã được cải thiện.

Linker

Trên windows/amd64, linker (với sự trợ giúp của compiler) giờ phát ra dữ liệu SEH unwinding theo mặc định, cải thiện việc tích hợp của các ứng dụng Go với Windows debugger và các công cụ khác.

Trong Go 1.21, linker (với sự trợ giúp của compiler) giờ có khả năng xóa các biến map toàn cục chết (không được tham chiếu), nếu số mục trong bộ khởi tạo biến đủ lớn, và nếu các biểu thức khởi tạo không có tác dụng phụ.

Thư viện chuẩn

Gói log/slog mới

Gói log/slog mới cung cấp structured logging với các cấp độ. Structured logging phát ra các cặp khóa-giá trị để cho phép xử lý nhanh, chính xác các lượng lớn dữ liệu log. Gói hỗ trợ tích hợp với các công cụ và dịch vụ phân tích log phổ biến.

Gói testing/slogtest mới

Gói testing/slogtest mới có thể giúp xác nhận các triển khai slog.Handler.

Gói slices mới

Gói slices mới cung cấp nhiều thao tác thông thường trên các slice, sử dụng các hàm generic hoạt động với slice của bất kỳ kiểu phần tử nào.

Gói maps mới

Gói maps mới cung cấp một số thao tác thông thường trên các map, sử dụng các hàm generic hoạt động với các map của bất kỳ kiểu khóa hoặc phần tử nào.

Gói cmp mới

Gói cmp mới định nghĩa ràng buộc kiểu Ordered và hai hàm generic mới LessCompare hữu ích với các kiểu có thứ tự.

Các thay đổi nhỏ trong thư viện

Như mọi khi, có nhiều thay đổi và cập nhật nhỏ trong thư viện, được thực hiện với cam kết tương thích của Go 1 được ghi nhớ. Ngoài ra cũng có nhiều cải thiện hiệu năng, không được liệt kê ở đây.

archive/tar

Triển khai interface io/fs.FileInfo được trả bởi Header.FileInfo giờ triển khai phương thức String gọi io/fs.FormatFileInfo.

archive/zip

Triển khai interface io/fs.FileInfo được trả bởi FileHeader.FileInfo giờ triển khai phương thức String gọi io/fs.FormatFileInfo.

Triển khai interface io/fs.DirEntry được trả bởi phương thức io/fs.ReadDirFile.ReadDir của io/fs.File được trả bởi Reader.Open giờ triển khai phương thức String gọi io/fs.FormatDirEntry.

bytes

Kiểu Buffer có hai phương thức mới: AvailableAvailableBuffer. Chúng có thể dùng cùng với phương thức Write để append trực tiếp vào Buffer.

context

Hàm mới WithoutCancel trả về bản sao của một context không bị hủy khi context gốc bị hủy.

Các hàm mới WithDeadlineCauseWithTimeoutCause cung cấp cách đặt nguyên nhân hủy context khi deadline hoặc bộ đếm thời gian hết hạn. Nguyên nhân có thể lấy lại bằng hàm Cause.

Hàm mới AfterFunc đăng ký một hàm chạy sau khi context bị hủy.

Một tối ưu hóa có nghĩa là kết quả của việc gọi BackgroundTODO và chuyển đổi chúng sang một kiểu dùng chung có thể được coi là bằng nhau. Trong các bản phát hành trước chúng luôn khác nhau. So sánh các giá trị Context cho tính bằng nhau chưa bao giờ được định nghĩa rõ ràng, vì vậy đây không được coi là thay đổi không tương thích.

crypto/ecdsa

PublicKey.EqualPrivateKey.Equal giờ thực thi trong thời gian không đổi.

crypto/elliptic

Tất cả phương thức Curve đã bị deprecated, cùng với GenerateKey, Marshal, và Unmarshal. Cho các thao tác ECDH, nên dùng gói crypto/ecdh mới thay thế. Cho các thao tác cấp thấp hơn, hãy dùng các module bên thứ ba như filippo.io/nistec.

crypto/rand

Gói crypto/rand giờ dùng system call getrandom trên NetBSD 10.0 trở lên.

crypto/rsa

Hiệu năng của các phép tính RSA riêng (giải mã và ký) giờ tốt hơn Go 1.19 cho GOARCH=amd64GOARCH=arm64. Nó đã bị thoái lui trong Go 1.20.

Do việc thêm các trường riêng vào PrecomputedValues, PrivateKey.Precompute phải được gọi để có hiệu năng tối ưu ngay cả khi deserializing (ví dụ từ JSON) một khóa riêng đã được tính trước.

PublicKey.EqualPrivateKey.Equal giờ thực thi trong thời gian không đổi.

Hàm GenerateMultiPrimeKey và trường PrecomputedValues.CRTValues đã bị deprecated. PrecomputedValues.CRTValues vẫn sẽ được điền khi PrivateKey.Precompute được gọi, nhưng các giá trị sẽ không được sử dụng trong quá trình giải mã.

crypto/sha256

Các phép tính SHA-224 và SHA-256 giờ dùng các hướng dẫn native khi có sẵn với GOARCH=amd64, cải thiện hiệu năng khoảng 3-4 lần.

crypto/tls

Các máy chủ giờ bỏ qua việc xác minh chứng chỉ client (bao gồm không chạy Config.VerifyPeerCertificate) cho các kết nối được tiếp tục, ngoài việc kiểm tra thời gian hết hạn. Điều này làm cho session ticket lớn hơn khi chứng chỉ client được sử dụng. Các client đã bỏ qua việc xác minh khi tiếp tục, nhưng giờ kiểm tra thời gian hết hạn ngay cả khi Config.InsecureSkipVerify được đặt.

Các ứng dụng giờ có thể kiểm soát nội dung của session ticket.

Để giảm khả năng session ticket được dùng như cơ chế theo dõi giữa các kết nối, máy chủ giờ phát hành ticket mới ở mỗi lần tiếp tục (nếu chúng được hỗ trợ và không bị tắt) và ticket không còn mang định danh cho khóa mã hóa chúng nữa. Nếu truyền số lượng lớn khóa cho Conn.SetSessionTicketKeys, điều này có thể dẫn đến chi phí hiệu năng đáng chú ý.

Cả client và máy chủ giờ triển khai extension Extended Master Secret (RFC 7627). Việc deprecated của ConnectionState.TLSUnique đã được hoàn nguyên, và giờ được đặt cho các kết nối được tiếp tục hỗ trợ Extended Master Secret.

Kiểu mới QUICConn cung cấp hỗ trợ cho các triển khai QUIC, bao gồm hỗ trợ 0-RTT. Lưu ý rằng đây không tự nó là triển khai QUIC, và 0-RTT vẫn chưa được hỗ trợ trong TLS.

Hàm mới VersionName trả về tên cho một số phiên bản TLS.

Các mã cảnh báo TLS được gửi từ máy chủ cho các lỗi xác thực client đã được cải thiện. Trước đây, các lỗi này luôn dẫn đến cảnh báo “bad certificate”. Giờ, một số lỗi sẽ dẫn đến các mã cảnh báo phù hợp hơn, được định nghĩa bởi RFC 5246 và RFC 8446:

  • Cho các kết nối TLS 1.3, nếu máy chủ được cấu hình yêu cầu xác thực client bằng RequireAnyClientCert hoặc RequireAndVerifyClientCert, và client không cung cấp bất kỳ chứng chỉ nào, máy chủ giờ sẽ trả về cảnh báo “certificate required”.
  • Nếu client cung cấp chứng chỉ không được ký bởi tập hợp CA tin cậy được cấu hình trên máy chủ, máy chủ sẽ trả về cảnh báo “unknown certificate authority”.
  • Nếu client cung cấp chứng chỉ đã hết hạn hoặc chưa có hiệu lực, máy chủ sẽ trả về cảnh báo “expired certificate”.
  • Trong tất cả các tình huống khác liên quan đến lỗi xác thực client, máy chủ vẫn trả về “bad certificate”.

crypto/x509

RevocationList.RevokedCertificates đã bị deprecated và được thay thế bằng trường RevokedCertificateEntries mới, là một slice của RevocationListEntry. RevocationListEntry chứa tất cả các trường trong pkix.RevokedCertificate, cũng như mã lý do thu hồi.

Các ràng buộc tên giờ được thực thi đúng cách trên các chứng chỉ không phải leaf, và không áp dụng cho các chứng chỉ nơi chúng được biểu đạt.

debug/elf

Phương thức mới File.DynValue có thể dùng để lấy các giá trị số được liệt kê với một dynamic tag đã cho.

Các cờ hằng số được phép trong dynamic tag DT_FLAGS_1 giờ được định nghĩa với kiểu DynFlag1. Các tag này có tên bắt đầu bằng DF_1.

Gói giờ định nghĩa hằng số COMPRESS_ZSTD.

Gói giờ định nghĩa hằng số R_PPC64_REL24_P9NOTOC.

debug/pe

Các lần thử đọc từ một phần chứa dữ liệu chưa khởi tạo bằng cách dùng Section.Data hoặc reader được trả bởi Section.Open giờ trả về lỗi.

embed

io/fs.File được trả bởi FS.Open giờ có phương thức ReadAt triển khai io.ReaderAt.

Gọi FS.Open.Stat sẽ trả về một kiểu giờ triển khai phương thức String gọi io/fs.FormatFileInfo.

encoding/binary

Biến mới NativeEndian có thể dùng để chuyển đổi giữa byte slice và số nguyên sử dụng endianness native của máy hiện tại.

errors

Lỗi mới ErrUnsupported cung cấp cách chuẩn hóa để cho biết rằng một thao tác được yêu cầu có thể không được thực hiện vì nó không được hỗ trợ. Ví dụ: lời gọi đến os.Link khi sử dụng hệ thống tệp không hỗ trợ hard link.

flag

Hàm mới BoolFunc và phương thức FlagSet.BoolFunc định nghĩa một flag không yêu cầu đối số và gọi một hàm khi flag được sử dụng. Điều này tương tự như Func nhưng cho boolean flag.

Định nghĩa flag (qua Bool, BoolVar, Int, IntVar, v.v.) sẽ panic nếu Set đã được gọi trên một flag có cùng tên. Thay đổi này được thiết kế để phát hiện các trường hợp thay đổi trong thứ tự khởi tạo gây ra các thao tác flag xảy ra theo thứ tự khác với mong đợi. Trong nhiều trường hợp, cách sửa vấn đề này là giới thiệu một dependency gói tường minh để sắp xếp đúng việc định nghĩa trước bất kỳ thao tác Set nào.

go/ast

Predicate mới IsGenerated báo cáo liệu một cây cú pháp tệp có chứa comment đặc biệt theo quy ước cho biết tệp được tạo bởi một công cụ hay không.

Trường mới File.GoVersion ghi lại phiên bản Go tối thiểu yêu cầu bởi bất kỳ directive //go:build hoặc // +build nào.

go/build

Gói giờ phân tích các build directive (comment bắt đầu bằng //go:) trong header tệp (trước khai báo package). Các directive này có sẵn trong các trường mới Package Directives, TestDirectives, và XTestDirectives.

go/build/constraint

Hàm mới GoVersion trả về phiên bản Go tối thiểu được ngụ ý bởi một biểu thức build.

go/token

Phương thức mới File.Lines trả về bảng số dòng của tệp theo cùng dạng được chấp nhận bởi File.SetLines.

go/types

Phương thức mới Package.GoVersion trả về phiên bản ngôn ngữ Go được dùng để kiểm tra gói.

hash/maphash

Gói hash/maphash giờ có triển khai Go thuần túy, có thể chọn bằng build tag purego.

html/template

Lỗi mới ErrJSTemplate được trả khi một action xuất hiện trong JavaScript template literal. Trước đây một lỗi không được export sẽ được trả về.

io/fs

Hàm mới FormatFileInfo trả về phiên bản được định dạng của FileInfo. Hàm mới FormatDirEntry trả về phiên bản được định dạng của DirEntry. Triển khai của DirEntry được trả bởi ReadDir giờ triển khai phương thức String gọi FormatDirEntry, và tương tự với giá trị DirEntry được truyền cho WalkDirFunc.

math/big

Phương thức mới Int.Float64 trả về giá trị dấu phẩy động gần nhất với số nguyên đa độ chính xác, cùng với thông tin về bất kỳ làm tròn nào đã xảy ra.

net

Trên Linux, gói net giờ có thể dùng Multipath TCP khi kernel hỗ trợ nó. Nó không được dùng theo mặc định. Để dùng Multipath TCP khi có sẵn trên client, hãy gọi phương thức Dialer.SetMultipathTCP trước khi gọi phương thức Dialer.Dial hoặc Dialer.DialContext. Để dùng Multipath TCP khi có sẵn trên máy chủ, hãy gọi phương thức ListenConfig.SetMultipathTCP trước khi gọi phương thức ListenConfig.Listen. Chỉ định network là "tcp" hoặc "tcp4" hoặc "tcp6" như thường lệ. Nếu Multipath TCP không được kernel hoặc remote host hỗ trợ, kết nối sẽ lặng lẽ fall back về TCP. Để kiểm tra liệu một kết nối cụ thể có đang sử dụng Multipath TCP hay không, hãy dùng phương thức TCPConn.MultipathTCP.

Trong bản phát hành Go tương lai, chúng tôi có thể bật Multipath TCP theo mặc định trên các hệ thống hỗ trợ nó.

net/http

Phương thức mới ResponseController.EnableFullDuplex cho phép các handler máy chủ đọc đồng thời từ body yêu cầu HTTP/1 trong khi viết phản hồi. Thông thường, HTTP/1 server tự động tiêu thụ bất kỳ body yêu cầu còn lại nào trước khi bắt đầu viết phản hồi, để tránh deadlock client cố viết yêu cầu đầy đủ trước khi đọc phản hồi. Phương thức EnableFullDuplex tắt hành vi này.

Lỗi mới ErrSchemeMismatch được trả bởi ClientTransport khi máy chủ phản hồi yêu cầu HTTPS bằng phản hồi HTTP.

Gói net/http giờ hỗ trợ errors.ErrUnsupported, sao cho biểu thức errors.Is(http.ErrNotSupported, errors.ErrUnsupported) sẽ trả về true.

os

Các chương trình giờ có thể truyền giá trị time.Time rỗng cho hàm Chtimes để giữ nguyên thời gian truy cập hoặc thời gian sửa đổi.

Trên Windows, phương thức File.Chdir giờ thay đổi thư mục hiện tại thành tệp, thay vì luôn trả về lỗi.

Trên các hệ thống Unix, nếu descriptor không chặn được truyền cho NewFile, gọi phương thức File.Fd giờ sẽ trả về descriptor không chặn. Trước đây descriptor được chuyển đổi sang chế độ blocking.

Trên Windows, gọi Truncate trên tệp không tồn tại trước đây tạo tệp rỗng. Giờ nó trả về lỗi cho biết tệp không tồn tại.

Trên Windows, gọi TempDir giờ dùng GetTempPath2W khi có sẵn, thay vì GetTempPathW. Hành vi mới là biện pháp tăng cường bảo mật ngăn chặn các tệp tạm thời được tạo bởi các quá trình chạy với tư cách SYSTEM bị truy cập bởi các quá trình không phải SYSTEM.

Trên Windows, gói os giờ hỗ trợ làm việc với các tệp có tên, được lưu trữ dưới dạng UTF-16, không thể được biểu diễn dưới dạng UTF-8 hợp lệ.

Trên Windows, Lstat giờ giải quyết symbolic link cho các đường dẫn kết thúc bằng dấu phân cách đường dẫn, nhất quán với hành vi của nó trên các nền tảng POSIX.

Triển khai interface io/fs.DirEntry được trả bởi hàm ReadDir và phương thức File.ReadDir giờ triển khai phương thức String gọi io/fs.FormatDirEntry.

Triển khai interface io/fs.FS được trả bởi hàm DirFS giờ triển khai các interface io/fs.ReadFileFSio/fs.ReadDirFS.

path/filepath

Triển khai interface io/fs.DirEntry được truyền cho đối số hàm của WalkDir giờ triển khai phương thức String gọi io/fs.FormatDirEntry.

reflect

Trong Go 1.21, ValueOf không còn ép buộc đối số của nó được cấp phát trên heap, cho phép nội dung của Value được cấp phát trên stack. Hầu hết các thao tác trên Value cũng cho phép giá trị bên dưới được cấp phát trên stack.

Phương thức Value mới Value.Clear xóa nội dung của map hoặc đặt nội dung của slice về zero. Điều này tương ứng với hàm built-in clear mới được thêm vào ngôn ngữ.

Các kiểu SliceHeaderStringHeader giờ bị deprecated. Trong code mới, ưu tiên dùng unsafe.Slice, unsafe.SliceData, unsafe.String, hoặc unsafe.StringData.

regexp

Regexp giờ định nghĩa các phương thức MarshalTextUnmarshalText. Chúng triển khai encoding.TextMarshalerencoding.TextUnmarshaler và sẽ được dùng bởi các gói như encoding/json.

runtime

Các stack trace dạng văn bản được tạo bởi chương trình Go, chẳng hạn như những gì được tạo khi crash, gọi runtime.Stack, hoặc thu thập goroutine profile với debug=2, giờ bao gồm ID của các goroutine đã tạo mỗi goroutine trong stack trace.

Các ứng dụng Go bị crash giờ có thể opt-in vào Windows Error Reporting (WER) bằng cách đặt biến môi trường GOTRACEBACK=wer hoặc gọi debug.SetTraceback("wer") trước khi crash. Ngoài việc bật WER, runtime sẽ hoạt động như với GOTRACEBACK=crash. Trên các hệ thống không phải Windows, GOTRACEBACK=wer bị bỏ qua.

GODEBUG=cgocheck=2, một trình kiểm tra kỹ lưỡng các quy tắc truyền con trỏ cgo, không còn có sẵn như một tùy chọn debug nữa. Thay vào đó, nó có sẵn như một thử nghiệm sử dụng GOEXPERIMENT=cgocheck2. Đặc biệt điều này có nghĩa là chế độ này phải được chọn tại thời điểm build thay vì thời gian khởi động.

GODEBUG=cgocheck=1 vẫn có sẵn (và vẫn là mặc định).

Kiểu mới Pinner đã được thêm vào gói runtime. Pinner có thể dùng để “pin” bộ nhớ Go để nó có thể được sử dụng tự do hơn bởi code không phải Go. Ví dụ: truyền các giá trị Go tham chiếu đến bộ nhớ Go được pin cho code C giờ được cho phép. Trước đây, truyền bất kỳ tham chiếu lồng nhau nào như vậy bị cấm bởi quy tắc truyền con trỏ cgo. Xem tài liệu để biết thêm chi tiết.

runtime/metrics

Một số metric GC nội bộ trước đây, như kích thước live heap, giờ có sẵn. GOGCGOMEMLIMIT cũng giờ có sẵn như metric.

runtime/trace

Thu thập trace trên amd64 và arm64 giờ phát sinh chi phí CPU nhỏ hơn đáng kể: cải thiện lên đến 10 lần so với bản phát hành trước.

Các trace giờ chứa các sự kiện stop-the-world tường minh cho mỗi lý do Go runtime có thể stop-the-world, không chỉ bộ gom rác.

sync

Các hàm mới OnceFunc, OnceValue, và OnceValues nắm bắt một cách sử dụng phổ biến của Once để khởi tạo lười biếng một giá trị khi sử dụng lần đầu.

syscall

Trên Windows, hàm Fchdir giờ thay đổi thư mục hiện tại thành đối số của nó, thay vì luôn trả về lỗi.

Trên FreeBSD, SysProcAttr có trường mới Jail có thể dùng để đặt tiến trình mới tạo vào môi trường jail.

Trên Windows, gói syscall giờ hỗ trợ làm việc với các tệp có tên, được lưu trữ dưới dạng UTF-16, không thể được biểu diễn dưới dạng UTF-8 hợp lệ. Các hàm UTF16ToStringUTF16FromString giờ chuyển đổi giữa dữ liệu UTF-16 và chuỗi WTF-8. Điều này tương thích ngược vì WTF-8 là siêu tập của định dạng UTF-8 được dùng trong các bản phát hành trước.

Một số giá trị lỗi khớp với errors.ErrUnsupported mới, sao cho errors.Is(err, errors.ErrUnsupported) trả về true.

  • ENOSYS
  • ENOTSUP
  • EOPNOTSUPP
  • EPLAN9 (chỉ Plan 9)
  • ERROR_CALL_NOT_IMPLEMENTED (chỉ Windows)
  • ERROR_NOT_SUPPORTED (chỉ Windows)
  • EWINDOWS (chỉ Windows)

testing

Tùy chọn mới -test.fullpath sẽ in tên đường dẫn đầy đủ trong các thông báo log test, thay vì chỉ tên cơ sở.

Hàm mới Testing báo cáo liệu chương trình có phải là test được tạo bởi go test hay không.

testing/fstest

Gọi Open.Stat sẽ trả về một kiểu giờ triển khai phương thức String gọi io/fs.FormatFileInfo.

unicode

Gói unicode và hỗ trợ liên quan trong toàn bộ hệ thống đã được nâng cấp lên Unicode 15.0.0.

Các nền tảng

Darwin

Như đã thông báo trong ghi chú phát hành Go 1.20, Go 1.21 yêu cầu macOS 10.15 Catalina trở lên; hỗ trợ các phiên bản trước đã bị ngừng.

Windows

Như đã thông báo trong ghi chú phát hành Go 1.20, Go 1.21 yêu cầu ít nhất Windows 10 hoặc Windows Server 2016; hỗ trợ các phiên bản trước đã bị ngừng.

ARM

Khi build bản phân phối Go với GOARCH=arm khi không chạy trên hệ thống ARM (tức là khi build cross-compiler sang ARM), giá trị mặc định cho biến môi trường GOARM giờ luôn được đặt thành 7. Trước đây giá trị mặc định phụ thuộc vào đặc điểm của hệ thống build.

Khi không build cross-compiler, giá trị mặc định được xác định bằng cách kiểm tra hệ thống build. Điều đó đúng trước đây và vẫn đúng trong Go 1.21. Điều đã thay đổi là hành vi khi build cross-compiler.

WebAssembly

Directive go:wasmimport mới giờ có thể được dùng trong chương trình Go để import các hàm từ WebAssembly host.

Go scheduler giờ tương tác hiệu quả hơn nhiều với JavaScript event loop, đặc biệt trong các ứng dụng chặn thường xuyên trên các sự kiện bất đồng bộ.

WebAssembly System Interface

Go 1.21 thêm một cổng thử nghiệm cho WebAssembly System Interface (WASI), Preview 1 (GOOS=wasip1, GOARCH=wasm).

Kết quả của việc thêm giá trị GOOS mới “wasip1”, các tệp Go có tên *_wasip1.go giờ sẽ bị bỏ qua bởi các công cụ Go ngoại trừ khi giá trị GOOS đó đang được sử dụng. Nếu bạn có tên tệp hiện có khớp với mẫu đó, bạn sẽ cần đổi tên chúng.

ppc64/ppc64le

Trên Linux, GOPPC64=power10 giờ tạo các hướng dẫn PC-relative, hướng dẫn có tiền tố, và các hướng dẫn Power10 mới khác. Trên AIX, GOPPC64=power10 tạo các hướng dẫn Power10, nhưng không tạo các hướng dẫn PC-relative.

Khi build các binary position-independent cho GOPPC64=power10 GOOS=linux GOARCH=ppc64le, người dùng có thể thấy kích thước binary giảm trong hầu hết các trường hợp, trong một số trường hợp là 3.5%. Các binary position-independent được build cho ppc64le với các giá trị -buildmode sau: c-archive, c-shared, shared, pie, plugin.

loong64

Cổng linux/loong64 giờ hỗ trợ -buildmode=c-archive, -buildmode=c-shared-buildmode=pie.