On context.Context keys uniqueness
After reading the blog post introducing context.Context, I got used to using integers as context.Context keys.
Here is a code sample taken from the blog post :
// userIPkey is the context key for the user IP address. Its value of zero is
// arbitrary. If this package defined other context keys, they would have
// different integer values.
const userIPKey key = 0func WithUserIP(ctx context.Context, userIP net.IP) context.Context {
return context.WithValue(ctx, userIPKey, userIP)
}func UserIPFromContext(ctx context.Context) (net.IP, bool) {
userIP, ok := ctx.Value(userIPKey).(net.IP)
return userIP, ok
}
This works fine when all context helper functions are located is the same package. But how would you guarantee key uniqueness when using multiple packages in a clean way ?
Fortunately, context.Context uses interface{} as a key parameter, and accepts everything that is comparable (i.e. that can be compared with ==):
func WithValue(parent Context, key interface{}, val interface{}) Context
func (c Context) Value(key interface{}) interface{}func (c *valueCtx) Value(key interface{}) interface{} {
if c.key == key {
return c.val
}
...
}
Struct are comparable, and two struct values are equal if their types match and their fields are equal. Therefore we could use :
type userIPKey struct{}func WithUserIP(ctx context.Context, userIP net.IP) context.Context {
return context.WithValue(ctx, userIPKey{}, userIP)
}func UserIPFromContext(ctx context.Context) (net.IP, bool) {
userIP, ok := ctx.Value(userIPKey{}).(net.IP)
return userIP, ok
}
Each package defines its own key types, and no conflicts are possible. Problem solved !