Tài liệu context giới hạn rõ: WithValue chỉ dành cho dữ liệu theo phạm vi một request đi xuyên qua biên process/API — request ID, trace ID, danh tính người dùng đã xác thực, locale. Không dùng nó để truyền tham số của hàm, và không dùng thay dependency injection: tham số nằm trong context thì compiler không kiểm tra được, thiếu là panic hoặc chạy sai lúc runtime.
Về key: WithValue so key bằng == trên any. Nếu dùng "user_id" kiểu string thì bất kỳ package nào khác cũng có thể ghi đè đúng key đó — hai thư viện độc lập vô tình giẫm lên nhau. Cách chuẩn là kiểu riêng, không export, nên bên ngoài package không thể tạo ra key trùng:
type ctxKey struct{}
var userKey ctxKey
func WithUser(ctx context.Context, u *User) context.Context {
return context.WithValue(ctx, userKey, u)
}
func UserFrom(ctx context.Context) (*User, bool) {
u, ok := ctx.Value(userKey).(*User)
return u, ok
}Luôn bọc bằng cặp hàm setter/getter như trên để nơi gọi không phải tự ép kiểu.
Hai lưu ý nữa: giá trị lưu vào phải bất biến và an toàn khi nhiều goroutine đọc; và ctx.Value duyệt ngược chuỗi context cha nên chi phí tăng theo số tầng — không nhét hàng chục giá trị vào một chain.