Context接口的设计

Ran*_*lue 3 go

我的问题是关于Context界面的设计选择.如果我想创建一个child上下文,parent我可以做类似的事情:

child, cancel := context.WithTimeout(parent, timeout)
Run Code Online (Sandbox Code Playgroud)

如果它是WithTimeout界面的一部分,它会不会更好,所以我们可以简单地写:

child, cancel := parent.WithTimeout(timeout)
Run Code Online (Sandbox Code Playgroud)

对我来说似乎更清洁.它更短,没有必要import context.

为什么生成子上下文的函数不是Context接口的一部分?

icz*_*cza 6

这是context.Context类型:

type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}
Run Code Online (Sandbox Code Playgroud)

这很简单.如果你要编写它的实现,你能做到吗?是的,很容易.由于没有"setter"方法,每个方法只能返回一个默认值/ 零值,这是一个"有效"的实现.这正是背景和TODO背景所做的(context.Background()context.TODO()).

如果要添加从现有的上下文(例如,等等)作为接口本身的一部分派生新上下文的函数,则需要为所有人提供(有效)实现,这是不可行的; 并且很少需要同时进行所有这些,因此浪费资源.context.WithCancel()context.WithDeadline()Context

扩展程序负责添加实现.如果你看一下如何实现context包:context/context.go你会看到不同context.Context的"衍生物"或"扩展"的不同实现:

// 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{}
}
Run Code Online (Sandbox Code Playgroud)

显然,我们可以组成其他有用的扩展,context.Context而这些扩展不在context包中.如果您有新想法,还会将其添加到Context界面吗?这将打破所有现有的实现,显然你的新想法没有在其他人的当前实现中实现.