First off, an apology for being rather unreliable with my “daily” emails. I’m in the middle of some traveling (was in the UK and Netherlands last week, and will be on a US road trip starting tomorrow), so I’m writing when I have a spare moment, which isn’t that often.
I’ve been talking about finding the ideal type for a context key. So far I’ve looked at empty structs (e.g. struct{}
), integers, and strings. Today I’ll look at one other type, before discussing conclusions: non-empty structs.
type contextKey struct{ name string }
var (
KeyUserID = &contextKey{"user_id"}
KeyTransactionID = &contextKey{"transaction_id"}
KeyMessageID = &contextKey{"message_id"}
)
This has been my default approach for years, based on having seen this used in the standard library.
But how does it stack up? Let’s see…
- Must be comparable.
✅ Check. Unlike pointers to empty structs, which may all point to the same memory location, teach key instance points to a distinct memory location, and is comparable.
- Use minimal memory.
✅ Yep. This approach I estimate would use 16-24 bytes per key instance, depending on architexture.
- Should be readable.
Yes!
fmt.Printf("failed to read context key %s", KeyMessageID)
// prints: failed to read context key &{message_id}
- Easy to declare multiple keys per package.
✅ Super easy!
- Nice if it works with
const
❌ NO!
Structs cannot be constants in Go.
Despite the lack of support for constants, this is still a strong candidate, and a pattern used frequently in the standard library.