2016-11-17 90 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)它更隱晦一點。