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.