
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 }

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.

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
