Golang 中国

context包 WithValue函数, 官方写了大量关于key应该是非导出的, 非go内置的的类型. 官方文档看了好几遍, 没明白强调key的类型的具体意义. 故求问.


aaaaaaaa 于 2018-01-08 14:55 修改
2 回复
heimeil
#1 heimeil • 2018-01-08 10:38

官方文档没有特别描述GC啊,我看见的是使用非内置类型是为了避免和其他包冲突,直接看源码:

// WithValue returns a copy of parent in which the value associated with key is
// val.
//
// Use context Values only for request-scoped data that transits processes and
// APIs, not for passing optional parameters to functions.
//
// The provided key must be comparable and should not be of type
// string or any other built-in type to avoid collisions between
// packages using context. Users of WithValue should define their own
// types for keys. To avoid allocating when assigning to an
// interface{}, context keys often have concrete type
// struct{}. Alternatively, exported context key variables' static
// type should be a pointer or interface.
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}
}

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

func (c *valueCtx) String() string {
    return fmt.Sprintf("%v.WithValue(%#v, %#v)", c.Context, c.key, c.val)
}

func (c *valueCtx) Value(key interface{}) interface{} {
    if c.key == key {
        return c.val
    }
    return c.Context.Value(key)
}

关键在L39,当前ctx没有还会去父ctx获取,和JS原型链调用类似,如果在不知情的情况下用了和父ctx相同的key并且是内置类型就可能会有异常情况,文档说用自定义类型来避免这种情况是用了interface的特性,看下面例子:

package main

import (
    "fmt"
)

func main() {
    type myInt int
    i := myInt(1)
    fmt.Println(1 == i)     // true
    fmt.Println(compare(i)) // false
    fmt.Println(compare(1)) // true
}

func compare(key interface{}) bool {
    return 1 == key
}

interface的比较不只比较值还比较类型,这就是文档说的用非内置类型来避免冲突。

aaaaaaaa
#2 aaaaaaaa • 2018-01-08 14:45

“1 :

十分感谢, 明白了;

// 关于GC ,我把collisions 看成collection

需要 登录 后方可回复, 如果你还没有账号你可以 注册 一个帐号。