英文:
Why return a func in Golang
问题
我最近在研究Golang的上下文(context),发现WithCancel()
的实现方式很有趣。
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
if parent == nil {
panic("cannot create context from nil parent")
}
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() { c.cancel(true, Canceled) }
}
WithCancel()
返回一个ctx和一个用于取消相同上下文的函数。为什么不像下面这样,将.Cancel()
作为类型本身的一个函数引入呢?
func (c *cancelCtx) Cancel() {
c.cancel(true, Canceled)
}
我理解使用函数作为返回类型可以根据运行时条件运行不同的函数,但这里没有动态性 - 它始终是相同的函数。这只是因为函数式编程范式吗?
参考:https://cs.opensource.google/go/go/+/master:src/context/context.go;l=232-239?q=context&ss=go%2Fgo
英文:
I was looking into golang contexts recently, and found that the WithCancel()
is implemented in an interesting way.
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
if parent == nil {
panic("cannot create context from nil parent")
}
c := newCancelCtx(parent)
propagateCancel(parent, &c)
return &c, func() { c.cancel(true, Canceled) }
}
WithCancel()
returns a ctx, and also a func to cancel the very same context. Why is this done rather than introducing the .Cancel()
as a func of the type itself, like
func (c *cancelCtx) Cancel() {
c.cancel(true, Canceled)
}
I understand using a func return type allows you to run a different func depending on runtime conditions, but there's no dynamic here - it's always the same func. Is this just because for the functional paradigm?
答案1
得分: 4
并非所有的上下文都可以取消。你可以认为对于那些不能取消的上下文,Cancel()
方法可以是一个空操作。
但是这样的话,每当你使用 context.Context
时都必须调用 Cancel()
,因为你不知道(也无法知道)它是否真的需要取消。这在很多情况下都是不必要的,会使代码变慢(取消函数通常是延迟调用的),并且会使代码变得臃肿。
此外,取消上下文的权力只属于其创建者。创建者可以选择通过传递/共享取消函数来分享这个责任,但如果不这样做,仅仅共享上下文本身是不允许(也不应该允许)取消它的。如果 Cancel()
是 context.Context
的一部分,这个限制就无法强制执行了。有关详细信息,请参阅 https://stackoverflow.com/questions/66679577/cancel-context-from-child/66679667#66679667。
接口,尤其是那些被广泛使用的接口,应该是小而精简的,不包含所有的、很少有用的东西。
英文:
Not all contexts are cancel-able. You could argue that for those that aren't, the Cancel()
method could be a no-op.
But then you would always have to call Cancel()
whenever you work with context.Context
because you don't (can't) know whether it truly needs cancelling. This would be unnecessary in a lot of cases, would make code slower (cancel functions are usually called deferred) and would bloat the code.
Also, the power of cancelling a context is for its creator only. The creator may choose to share this responsibility by passing / sharing the cancel function, but if doesn't, sharing the context alone does not allow (should not allow) cancelling it. If Cancel()
would be part of context.Context
, this restriction could not be enforced. For details, see https://stackoverflow.com/questions/66679577/cancel-context-from-child/66679667#66679667.
Interfaces–especially those widely used–should be small and a minimum, not containing all, rarely useful things.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论