上下文界面的设计 [英] Design of Context interface

查看:149
本文介绍了上下文界面的设计的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题是关于 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/#WithCancel =nofollow noreferrer> context.WithCancel() ,< a href =https://golang.org/pkg/context/#WithDeadline =nofollow noreferrer> 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆