Hi, this works fine, but it incurs an extra allocation (AFAIK both for storing the data, and for looking it up). requestContext is not zero-sized, so to store it in an interface{}, a new value must be allocated and put into the interface. This also has to happen on lookup (I don't think the compiler optimizes that, today), because you need to convert it to interface{} when passing it to `Value`. The recommended way
type ctxKey struct{} type requestContext struct { requestID string requestID } ctx := context.WithValue(req.Context(), ctxKey{}, requestContext{"request-123-abc", "client-451"}) does not have this drawback - zero-sized values are special, because there can only be one of them, so the compiler is free to re-use the same address. So, a conversion of a zero-sized value to ctxKey{} is free. I would also argue, that the code is clearer and safer that way - because there can only be one value of type ctxKey{}, you don't have to wonder what would happen if you use different keys of the same type - and fmt.Println only prints the type-name of keys, not the actual value ( https://play.golang.org/p/pAj6RclqAGw), so if you encounter a bug with unexpected context-contents, it's just one less thing to worry about. So, yes, your way absolutely works. I would still strongly recommend going the "official" route. It's one line of additional overhead, but there are concrete technical benefits (as well as just the general benefits of uniformity). On Thu, Jan 7, 2021 at 12:09 AM Amit Saha <amitsaha...@gmail.com> wrote: > On Thu, Jan 7, 2021 at 10:01 AM Axel Wagner > <axel.wagner...@googlemail.com> wrote: > > > > Why do you need fields? If you need fields, you are likely putting too > many things into your context (note, that the lookup is O(N), with N being > the number of distinct keys - so you want the number of distinct keys to be > small). The intended use of `context.WithValue` is to only have one key per > "use-case" (normally, that means one key per package) and then store the > actual data in the value. > > > > So, yes, you *can* have fields and if you have fields and re-use one > type for many keys that way. And if you do that, you need to specify the > exact field values on the lookup as well. But if you want "many keys" from > a single type, that's a code-smell and I would suggest to change your > design. If you think you need it, feel free to expand on your use-case and > we might come up with a better solution :) > > This is what I have now in a HTTP handler function: > > Attach the data: > > c := requestContext{ > requestID: "request-123-abc", > clientID: "client-451", > } > > currentCtx := req.Context() > newCtx := context.WithValue(currentCtx, requestContext{}, c) > req = req.WithContext(newCtx) > > > Retrieve the data somewhere else during processing the request: > > ctx := req.Context() > v := ctx.Value(requestContext{}) > if m, ok := v.(requestContext); ok { > log.Printf("Processing request: %v", m) > } > > Is this inefficient? > > > > > > > > > > On Wed, Jan 6, 2021 at 11:52 PM Amit Saha <amitsaha...@gmail.com> wrote: > >> > >> On Thu, Jan 7, 2021 at 9:48 AM Axel Wagner > >> <axel.wagner...@googlemail.com> wrote: > >> > > >> > > >> > > >> > On Wed, Jan 6, 2021 at 11:39 PM Amit Saha <amitsaha...@gmail.com> > wrote: > >> >> > >> >> Is it fair to say then that any user-defined type here is acceptable > as a key? > >> > > >> > > >> > No. You can create a user-defined type out of *any* type T, by just > writing `type X T`. In particular, you can write `type X func()` and get an > incomparable user-defined type. > >> > > >> > I highly recommend sticking to the recommendation from the docs: Use > `type ctxKey struct{}` as a key type and `ctxKey{}` as the key - it's > comparable and the only value equal to `ctxKey{}` is `ctxKey{}`, which > gives exactly the desirable semantics. And as it's zero-sized, it also > doesn't occur any allocation (at least with gc, all zero-sized objects have > the same address). You could also use `[0]int` or similar, but `struct{}` > is very common for use-cases like this. > >> > >> Thanks. If I wanted to have a struct like this > >> > >> type myReqContext struct { > >> ID1 string > >> ID2 string > >> } > >> > >> Would the correct key and value be: myReqContext{}, myReqContext{ID1: > >> "abcd", ID2: "defg"}? > >> > >> The key isn't zero value any more, or is it? If so, should I have a > >> dedicated empty struct for the key? > >> > >> > >> > >> > > >> >> > >> >> > >> >> > >> >> >> > >> >> >> Thanks, > >> >> >> Amit. > >> >> >> > >> >> >> -- > >> >> >> You received this message because you are subscribed to the > Google Groups "golang-nuts" group. > >> >> >> To unsubscribe from this group and stop receiving emails from it, > send an email to golang-nuts+unsubscr...@googlegroups.com. > >> >> >> To view this discussion on the web visit > https://groups.google.com/d/msgid/golang-nuts/CANODV3kUmtJvG9Lfys_HXfedwnm54neA6uub6cY1aiz%2B9w5DUA%40mail.gmail.com > . > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEkBMfHTx1H_xEYwyBK9SiQv9GchZMnfuJMceqhA%3DqoeotHaJA%40mail.gmail.com.