2016-11-17 87 views
3

我的问题是关于Context interface的设计选择。如果我想创建一个从parent一个child方面,我可以这样做:上下文界面设计

child, cancel := context.WithTimeout(parent, timeout) 

,那岂不是更好,如果WithTimeout是接口的一部分,所以我们可以简单地写:

child, cancel := parent.WithTimeout(timeout) 

它对我来说似乎非常干净。它更短,并且不需要import context

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

+0

有趣的问题,但 - 我认为 - 由于是基于意见的主题。也许新的[softwareengineering.stackexchange.com](http://softwareengineering.stackexchange.com/)会更好;我不知道。 –

+1

@KonradRudolph我认为这不太适合软件工程。除非碰巧有Go语言开发人员,否则没有人可以提供正确的答案,并且它变成主要基于意见或请求提供答案的资源。如果它在堆栈溢出的话题不在话题上,我会建议将它发布到开发团队常去的某种Go社区或邮件列表中。 –

回答

6

这是context.Context类型:

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

很简单。如果你要写一个实现它,你能做到吗?是的,很容易。由于没有“setter”方法,每种方法都可以返回一个默认的/ zero value,这是一个“有效的”实现。这正是背景和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{} 
} 

显然,我们可以弥补其他有用的扩展context.Context这是不在context包中。如果你有一个新的想法,你是否也会添加到Context界面? 这会破坏所有现有的实现,显然你的新想法并未在其他人的当前实现中实现。

1

恕我直言,有2个原因:

  1. 这是因为WithContext无关与parent - 例如父母不应该需要也不应该有任何关于您可以从中创建子环境的事实。 Go的意识形态界面应该尽可能小。

  2. 它更具有可读性,并且清楚你作为输出得到了什么。在当前的实施中,someVar, _ := context.WithTimeout(value)被认为是some variable is a new (:=) context with a timeout。在你的建议版本中,它是someVar, _ := parent.WithTimeout(value)它更隐晦一点。