go通过context.WithValue传递指针
本文发布于 3 年前, 内容可能已经过时或失效!
### Go - Context: 信息穿透上下文 #### 使用场景 * 上下文传递信息(request-scoped),比如处理http请求、在请求处理链路上传递信息; * 控制子goroutine的运行; * 超时控制的方法调用(timeout); * 可以取消的方法调用(cancel); #### WithValue-传递上下文 以下是传递上下文方式 ```go ctx = context.TODO() ctx = context.WithValue(ctx, "key1", "0001") ctx = context.WithValue(ctx, "key2", "0001") ctx = context.WithValue(ctx, "key3", "0001") ctx = context.WithValue(ctx, "key4", "0004") fmt.Println(ctx.Value("key1")) ``` #### WithValue-通过透传指针参数(ctx.Value的值需要变化) **context通过透传指针参数可便于函数内外部修改与接收** **应用场景: (ctx.Value的值需要变化)** * 外部修改ctx.Value的值: 内部可以获取参数的值改变(比如需提前cancel并需改变某个透传的值) * 内部修改ctx.Value的值: 外部可以获取参数的值改变(内部执行到某位置并修改了透传的值) ### 示例 ```go package main import ( "context" "fmt" "time" ) // golang-context通过透传指针参数可便于函数内外部修改与接收 // 应用场景: (ctx.Value的值需要变化) // 外部修改ctx.Value的值: 内部可以获取参数的值改变(比如需提前cancel并需改变某个透传的值) // 内部修改ctx.Value的值: 外部可以获取参数的值改变(内部执行到某位置并修改了透传的值) func main() { // 初始cancel context ctx, cancel := context.WithCancel(context.Background()) // 预先设置传递参数 params := make([]string, 0) results := make([]any, 0) ctx = context.WithValue(ctx, "params", ¶ms) // 指针,调用内修改,外部直接使用其值 ctx = context.WithValue(ctx, "results", &results) // 指针,外部直接修改,调用内获取值 // 手动触发cancel go func() { time.Sleep(1 * time.Second) // 这时ctx.Value("params")已被函数内修改,newParams和params一致 fmt.Println("params", params) newParams := ctx.Value("params").(*[]string) fmt.Println("newParams", newParams) // 直接修改results,这时ctx.Value("results")已修改 results = []any{"1", "2", "3"} fmt.Println("results", results) // 调用cancel,提前结束testContextValue cancel() }() // 执行 newResults := testContextValue(ctx, 20*time.Second) // 结果 &["1", "2", "3"] fmt.Println("newResults", newResults) } // 应用场景 func testContextValue(ctx context.Context, timeout time.Duration) (resp *[]any) { // code before ... // 测试修改Context参数值 oldIds, ok := ctx.Value("params").(*[]string) if ok { *(oldIds) = []string{"a", "b", "c"} } // 阻塞或提前cancel select { case <-ctx.Done(): // 主动cancel // 主动调用cancelFunc前可先更改context参数值, // 主动停止时设置响应结果,通过context接收数据 resp, _ = ctx.Value("results").(*[]any) case <-time.After(timeout): // 阻塞 } // after code ... return } ```