上下文界面的设计 [英] Design of Context interface
问题描述
我的问题是关于 Context
界面。如果我想从父母
创建一个子
上下文,我可以这样做:
child,cancel:= context.WithTimeout(parent,timeout)
如果 WithTimeout
是接口的一部分,那么它会更好吗,这样我们可以简单地写出:
child,取消:= parent.WithTimeout(超时)
它对我来说似乎更加清洁。它更短,并且不需要 import context
。
为什么函数不生成子上下文部分上下文
接口?
这是 context.Context
类型:
类型上下文接口{
截止日期()(截止时间time,time,ok bool)
Done()< chan struct {}
Err()错误
接口{接口{}
}
很简单。如果你要写一个实现它,你能做到吗?是的,很容易。由于没有setter方法,每种方法都可以返回默认/ 零值,这是一个有效的实现。这正是背景和TODO上下文所做的事情( 如果你想从现有的函数中添加派生新上下文的函数(例如 context.Background()
和 context.TODO()
,< a href =https://golang.org/pkg/context/#WithDeadline =nofollow noreferrer>
context.WithCancel()
context.WithDeadline()
等)作为 Context
接口本身的一部分,这将需要为所有人提供(有效的)实现,这是不可行的;而且它们同时也是很少需要的,所以这会浪费资源。
扩展负责添加实现。如果你看看 context
包装已实施: context / context.go
,您会看到不同的<衍生型>或扩展名的 context.Context
实现:
// emptyCtx永远不会被取消,没有值,也没有最后期限。它不是
// struct {},因为这种类型的变量必须有不同的地址。
type emptyCtx int
// cancelCtx可以被取消。取消时,它也会取消任何实施取消操作的子
//。
类型cancelCtx结构{
上下文
完成chan struct {} //由第一次取消调用关闭。
mu sync.Mutex
children map [canceler] bool //由第一个取消调用设置为nil
err错误//由第一个取消调用设置为非零
}
//一个timerCtx带有一个定时器和一个截止日期。它嵌入一个cancelCtx到
//实现Done和Err。它通过停止计时器来实现取消,然后
//委托给cancelCtx.cancel。
type timerCtx struct {
cancelCtx
timer * time.Timer //在cancelCtx.mu下。
截止时间。时间
}
// valueCtx携带一个键值对。它为该键实现Value,
//将所有其他调用委托给嵌入式上下文。
type valueCtx struct {
上下文
key,val interface {}
}
显然我们可以为 context.Context
组成其他有用的扩展,它们不在上下文中
包。如果你有一个新的想法,你是否也将它添加到 Context
界面? 那会破坏所有现有的实现,显然你的新想法并未在别人当前的实现中实现。
My question is about a design choice for the Context
interface. If I want to create a child
context from a parent
I can do something like:
child, cancel := context.WithTimeout(parent, timeout)
Wouldn't it be nicer if WithTimeout
was part of the interface, so that we could simply write:
child, cancel := parent.WithTimeout(timeout)
It seems so much cleaner to me. It is shorter, and there is no need to import context
.
Why are the functions to produce child contexts not part of the Context
interface?
This is the context.Context
type:
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}
}
It's simple. If you were to write an implementation of it, could you do it? Yes, easily. As there are no "setter" methods, each method can just return a default / zero value, and it's a "valid" implementation. That's exactly what the background and TODO contexts do (context.Background()
and context.TODO()
).
If you would add the functions that derive new context from an existing one (e.g. context.WithCancel()
, context.WithDeadline()
etc.) as part of the Context
interface itself, that would require to provide a (valid) implementation for all, which is not feasible; and also all of them at the same time is rarely needed, so it would be a waste of resources.
Extensions are responsible to add the implementations. If you look at how the context
package is implemented: context/context.go
, you'll see different context.Context
implementations for the different "derivatives" or "extensions":
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
// struct{}, since vars of this type must have distinct addresses.
type emptyCtx int
// A cancelCtx can be canceled. When canceled, it also cancels any children
// that implement canceler.
type cancelCtx struct {
Context
done chan struct{} // closed by the first cancel call.
mu sync.Mutex
children map[canceler]bool // set to nil by the first cancel call
err error // set to non-nil by the first cancel call
}
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
// implement Done and Err. It implements cancel by stopping its timer then
// delegating to cancelCtx.cancel.
type timerCtx struct {
cancelCtx
timer *time.Timer // Under cancelCtx.mu.
deadline time.Time
}
// A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context.
type valueCtx struct {
Context
key, val interface{}
}
Obviously we can make up other useful extensions for context.Context
which are not in the context
package. If you have a new idea, would you also add that to the Context
interface? That would break all existing implementations, as obviously your new idea is not implemented in others' current implementations.
这篇关于上下文界面的设计的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!