Go Generics: Patterns thực tế cho code tái sử dụng

Go Generics ra mắt Go 1.18 cho phép viết code tái sử dụng với type parameters thay vì interface{} + reflection. Trước generics, lập trình viên Go phải viết lại hàm cho mỗi kiểu dữ liệu, dẫn đến code trùng lặp hoặc chấp nhận runtime overhead. Go generics giải quyết triệt để vấn đề này tại compile time, giữ performance tĩnh của Go.

Type Parameters cơ bản

Go generics giới thiệu type parameter list trong ngoặc vuông sau tên hàm hoặc kiểu. Cú pháp:

func Map[T any, U any](s []T, f func(T) U) []U

Hàm Map nhận slice bất kỳ kiểu T, áp dụng hàm f, trả slice kiểu U. any là alias cho interface{} — không ràng buộc kiểu. Compiler sinh mã riêng cho mỗi cặp (T, U) cụ thể được gọi.

Constraints

Ngoài any, Go cung cấp predeclared constraints: comparable (có thể so sánh bằng == hoặc !=), ordered (có thể so sánh < >), và custom interface. Ví dụ constraint cho type có phương thức String():

type Stringer interface { String() string }

Code example Go generics function syntax với type parameters và constraints

Patterns thực tế cho code tái sử dụng

1. Generic Map / Filter / Reduce

Trước generics, bạn dùng reflect hoặc viết lại MapInt, MapString. Bây giờ một hàm duy nhất:

func Filter[T any](s []T, pred func(T) bool) []T

Filter slice bất kỳ kiểu bằng predicate. Compiler tối ưu hóa, không reflection.

2. Generic Queue / Stack

Container type-safe mà không cần interface{}:

type Stack[T any] struct { items []T }

Stack ép kiểu tại compile time. Pop/Push không cần type assertion.

3. Generic Error Wrapping

Hàm Wrap[T error](err error, msg string) T hoặc generic Result[T] kiểu Rust. Không cần định nghĩa IntError, StrError riêng.

Biểu đồ so sánh code trước và sau generics: function duplication vs generic single implementation

Type Inference

Go compiler suy luận type arguments từ context. Map(s, func(i int) int { return i * 2 }) — compiler biết T=int từ kiểu slice s. Không cần ghi Map[int, int](s, ...) trừ khi compiler không suy luận được.

Inline và khi nào dùng

Go compiler inline generic functions. Performance gần với code tường minh. Dùng generics khi:

  • Container cần type-safe (slice, map, tree, queue).
  • Hàm thuật toán chung (Map, Filter, Reduce, Sort).
  • Interface chỉ dùng cho 1-2 hàm (thay vì interface lớn).

Khi nào KHÔNG dùng

Đừng abuse generics. Tránh generic cho:

  • Logic business chỉ áp dụng 1 kiểu cụ thể.
  • Interface có nhiều method, nên define concrete type rõ ràng.
  • Code đọc khó vì type parameter quá phức tạp (type inference mất, bug khó trace).

So sánh với Rust / C++ templates

Go generics an toàn hơn: không code bloat, không SFINAE, không specialization phức tạp. Rust có monomorphization + trait system mạnh hơn, nhưng complexity cao. Go generics giữ “boring” — compile, fail nếu không match, không template metaprogramming.

Kết luận

Go generics là bước ngoặt giúp codebase Go sạch hơn, DRY hơn mà vẫn giữ performance tĩnh. Học pattern căn bản: type parameters, constraints, type inference, container generic. Áp dụng vào Map/Filter/Reduce, Queue, Result — những nơi interface{} đang gây pain point. Dùng đúng mục đích, generics sẽ giảm boilerplate đáng kể mà không làm mất đi tính đơn giản của Go.

Nguồn: Go Blog – Generics in Go 1.18, Go Blog – When to Use Generics, Go Spec – Type Parameters

Tôi là một lập trình viên IOS. Code chính là IOS nhưng thỉnnh thoảng vẫn đá sang Android hoặc web. Mặc dù không quá thông thạo nhưng tôi sẽ chia sẻ những kiến thức mà mình đã tìm hiểu, áp dụng qua.

Bài viết liên quan

Biome.js: Công cụ Linter và Formatter JavaScript/TypeScript Nhanh Như Rust Thay Thế ESLint và Prettier

Biome là một web toolchain (formatter + linter + LSP) được viết bằng Rust, hỗ trợ JavaScript, TypeScript, JSX, TSX, JSON, HTML, CSS, và GraphQL. Được ra mắt năm 2023,…

Xem thêm

Supabase: Open-source Firebase Alternative với PostgreSQL

Supabase là gì: Firebase Alternative mã nguồn mở dựa trên PostgreSQL Supabase là nền tảng phát triển ứng dụng mã nguồn mở (Apache 2.0, hơn 108K ⭐ trên GitHub) dựa…

Xem thêm

Drizzle ORM: TypeScript ORM hiện đại cho PostgreSQL và MySQL

Drizzle ORM là một ORM hiện đại dành cho TypeScript, hỗ trợ PostgreSQL, MySQL, SQLite và các database serverless như Turso, Neon, Cloudflare D1. Với kích thước chỉ ~7.4KB gzipped,…

Xem thêm
0 0 đánh giá
Article Rating
Theo dõi
Thông báo của
guest
0 Comments
Cũ nhất
Mới nhất Được bỏ phiếu nhiều nhất