type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{} }其中:
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
WithCancel 返回帶有新 Done 通道的父節點的副本,當呼叫返回的 cancel 函數或當關閉父上下文的 Done 通道時,將關閉返回上下文的 Done 通道,無論先發生什麼情況。package main import ( "context" "fmt" ) func main() { gen := func(ctx context.Context) <-chan int { dst := make(chan int) n := 1 go func() { for { select { case <-ctx.Done(): return // return結束該goroutine,防止洩露 case dst <- n: n++ } } }() return dst } ctx, cancel := context.WithCancel(context.Background()) defer cancel() // 當我們取完需要的整數後呼叫cancel for n := range gen(ctx) { fmt.Println(n) if n == 5 { break } } }上面的程式碼中,gen 函數在單獨的 Goroutine 中生成整數並將它們傳送到返回的通道,gen 的呼叫者在使用生成的整數之後需要取消上下文,以免 gen 啟動的內部 Goroutine 發生洩漏。
go run main.go
1
2
3
4
5
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
WithDeadline 函數會返回父上下文的副本,並將 deadline 調整為不遲於 d。如果父上下文的 deadline 已經早於 d,則 WithDeadline(parent, d) 在語意上等同於父上下文。當截止日過期時,當呼叫返回的 cancel 函數時,或者當父上下文的 Done 通道關閉時,返回上下文的 Done 通道將被關閉,以最先發生的情況為準。package main import ( "context" "fmt" "time" ) func main() { d := time.Now().Add(50 * time.Millisecond) ctx, cancel := context.WithDeadline(context.Background(), d) // 儘管ctx會過期,但在任何情況下呼叫它的cancel函數都是很好的實踐。 // 如果不這樣做,可能會使上下文及其父類別存活的時間超過必要的時間。 defer cancel() select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) } }執行結果如下:
go run main.go
context deadline exceeded
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
WithTimeout 函數返回 WithDeadline(parent, time.Now().Add(timeout))。package main import ( "context" "fmt" "time" ) func main() { // 傳遞帶有超時的上下文 // 告訴阻塞函數在超時結束後應該放棄其工作。 ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) defer cancel() select { case <-time.After(1 * time.Second): fmt.Println("overslept") case <-ctx.Done(): fmt.Println(ctx.Err()) // 終端輸出"context deadline exceeded" } }執行結果如下:
go run main.go
context deadline exceeded
func WithValue(parent Context, key, val interface{}) Context
WithValue 函數接收 context 並返回派生的 context,其中值 val 與 key 關聯,並通過 context 樹與 context 一起傳遞。這意味著一旦獲得帶有值的 context,從中派生的任何 context 都會獲得此值。不建議使用 context 值傳遞關鍵引數,函數應接收簽名中的那些值,使其顯式化。{ }
時進行分配,上下文鍵通常具有具體型別 struct{}。或者,匯出的上下文關鍵變數的靜態型別應該是指標或介面。package main import ( "context" "fmt" ) func main() { type favContextKey string // 定義一個key型別 // f:一個從上下文中根據key取value的函數 f := func(ctx context.Context, k favContextKey) { if v := ctx.Value(k); v != nil { fmt.Println("found value:", v) return } fmt.Println("key not found:", k) } k := favContextKey("language") // 建立一個攜帶key為k,value為"Go"的上下文 ctx := context.WithValue(context.Background(), k, "Go") f(ctx, k) f(ctx, favContextKey("color")) }執行結果如下:
go run main.go
found value: Go
key not found: color