On Thu, Jan 7, 2021 at 10:20 AM Axel Wagner <axel.wagner...@googlemail.com> wrote: > > 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).
Your previous reply made me think of the same approach - use a separate type for key. > 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 I agree, I was thinking the same. Thank you. > > > 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/CANODV3%3DKZHZ_O2JDvC0F3wT3k725iHzgD79qXoHpWjY4vvT%3DMw%40mail.gmail.com.