引用来自 golang team 成员 Sajmani 的 issues 回答
Yes, the impedance mismatch is primarily a concern for exported types. The scenario I'm worried about is:
- package foo defines type Context that contains a context.Context and, say, method Foo() *Foo, for accessing foo-specific data.
- package bar defines type Context that contains a context.Context and, say, method Bar() *Bar, for accessing bar-specific data.
- Some function that accepts a foo.Context needs to call a bar.Context. Passing just the context.Context loses the *Foo and doesn't necessarily know what to pass for *Bar:
func F(fctx foo.Context) { bctx := bar.NewContext(fctx.Context(), nil /*the *Bar value*/) G(bctx) }
Furthermore, if G later calls a function that expects a foo.Context, the *Foo that should have been plumbed through has been lost:
func G(bctx bar.Context) { fctx := foo.NewContext(bctx.Context(), nil /*the *Foo value*/) H(fctx) }
The point of the context.Context.Value design is that packages foo and bar don't care about any of this. Their values propagate through layers of the call stack without intersecting or interfering with each other. This is exactly what you want for things like trace IDs, authentication scopes, profiling tags. But this is not what you should use for API-visible options. The "keep Context out of structs" restriction is a simple rule to follow that helps users avoid problems like this, but it is overly restrictive. The real guidelines are harder to articulate, but perhaps we should try harder to do so.
我个人的理解是:
-
context.Context
设计的目的是简明描述调用栈中各层级间的关系,传参是达到这一目的的一种简单方式。 -
不在struct中存 context.Context
只是一种为实现上述目的的编码约束,并不涉及运行机制。 - 所以,其实只要自己愿意,也是可以违反的。
有疑问加站长微信联系(非本文作者)