美文网首页
context 使用简介

context 使用简介

作者: juniway | 来源:发表于2017-10-24 17:56 被阅读34次

简介

在使用 Go 语言进行网络编程时,经常需要使用 context 来传递跟每个 Request 相关的信息,因此它是一个非常重要的结构。
在 Go 1.7 中 context 已经进入标准库 context,直接 import "context" 就可以使用。

这篇文章主要通过解析标准库提供的 context.go 源码来掌握 context 的使用方法。

Context 源码解析

从源码中可知,Context 是定义为一个接口类型 interface{}

// A Context carries a deadline, a cancelation signal, and other values across API boundaries.
// Context's methods may be called by multiple goroutines simultaneously.
type Context interface {
    Deadline() (deadline time.Time, ok bool)
    Done() <-chan struct{}
    Err() error
    Value(key interface{}) interface{}
}

标准库用了一个 emptyCtx 来作为默认的 implementer

type emptyCtx int
func (*emptyCtx) Deadline() (deadline time.Time, ok bool) {
    return
}

func (*emptyCtx) Done() <-chan struct{} {
    return nil
}
...

由于默认的 emptyCtx 是未导出的,因此,标准库又提供了两个公共的函数 Background 和 TODO 来访问这个 implementer。

var (
    background = new(emptyCtx)
    todo       = new(emptyCtx)
)

func Background() Context {
    return background
}

func TODO() Context {
    return todo
}

此外,还提供了一个 CancelFunc 的回调函数原型,WithCancel() 函数可用来给 Context 注册一个 cancel 函数。
还提供了另外几个其他的 With 函数,分别是 WithDeadline(), WithTimeout() 和 WithValue()。
WithDeadline 和 WithTimeout 都是给 parent Context 加上一个 timeout 并返回一个 cancel func。

WithValue() 复制原 context,并把一对 key、value 保存到副本中。

func WithValue(parent Context, key, val interface{}) Context {
    if key == nil {
        panic("nil key")
    }
    if !reflect.TypeOf(key).Comparable() {
        panic("key is not comparable")
    }
    return &valueCtx{parent, key, val}
}

由于 Context 本身是 interface{} 接口类型,没法保存 key/value,其实质是通过一个包的私有类型 valueCtx 来保存的,如下:

// 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{}
}

可见,通过传入一个 parent context,以及 key/value,最终会保存在 valueCtx 中并返回。

http.Request 中对 Context 的使用

下面通过对 http.Request 的分析来学习 Context 的常见使用方式。

http.Request 是一个结构体类型,其有一个成员就是 ctx Context 接口类型(私有成员)。通过包方法 http.NewRequest() 来创建。创建时默认 Context 成员未初始化,也就是 nil。
request 对象提供了一个公共方法 Context() 来访问私有的 ctx 成员,如下:

func (r *Request) Context() context.Context {
    if r.ctx != nil {
        return r.ctx
    }
    return context.Background()
}

可见,默认创建好的 request, 其 ctx 是 Background() 。

Request 结构体提供了 WithContext(ctx context.Context) 方法用来给自己的 ctx 成员赋值。

// WithContext returns a shallow copy of r with its context changed
// to ctx. The provided ctx must be non-nil.
func (r *Request) WithContext(ctx context.Context) *Request {
    if ctx == nil {
        panic("nil context")
    }
    r2 := new(Request)
    *r2 = *r
    r2.ctx = ctx
    return r2
}

相关文章

  • context 使用简介

    简介 在使用 Go 语言进行网络编程时,经常需要使用 context 来传递跟每个 Request 相关的信息,因...

  • rxAndroid 和ActionMode实现简易文件浏览器

    ActionMode简介 Android 3.0以前,我们处理列表的长按事件经常使用Context Menu,An...

  • 03Gin源码解读

    简介 Context 初始化 Context 之请求参数获取 Context 之模型绑定和验证 Context 之...

  • Context Hook

    Context Hook 用于获取上下文数据 使用context: 使用Context Hook:

  • react Context

    如何使用context 创建context对象 把想要用context的数据的节点使用context.Provid...

  • Android Context简介

    目录 什么是Android Context Context意味着一个场景,一个场景就是我们和软件进行交互的一个过程...

  • Android Context简介

    概述 Android程序和Java程序一个不同的地方在于Android程序不能仅仅通过一个main方法就启动起来,...

  • Android Context简介

    Context在整个系统里的核心表现形式如下图: 简单来讲,Context是一个抽象类,定义了一系列的抽象方法,它...

  • 进阶之光笔记二

    第五章 理解上下文Context Context的关联类 Context使用场景:1.使用Context调用方法,...

  • $.proxy

    $.proxy( function, context ):使用context代替function中的context...

网友评论

      本文标题:context 使用简介

      本文链接:https://www.haomeiwen.com/subject/fhsxpxtx.html