「这是我参与2022首次更文挑战的第6天,活动详情查看:2022首次更文挑战」。
context想必每个go语言开发者都不陌生,我们通常会在每个函数的第一个参数,以及打日志时见到他,那么为什么我们不把他放在结构体中的,当调用结构体的某个函数时,就可以很方便的使用他(打日志)。
举个例子
type Worker struct {
ctx context.Context
}
func New(ctx context.Context) *Worker {
return &Worker{ctx: ctx}
}
在这种情况下,worker的函数无需context作为参数,但这也会给用户带来困惑。我们都知道context一般用处有三个:
- 跨服务传递信息
- 控制协程关闭
- 控制超时取消
对于后两者,需要WithCancel和WithTimeout的方法实现,那一个开发者看到这行代码的时候,他就不知道自己是否需要设置一个超时时间,或者声明cancel方法。这会令开发者十分困惑。同时,将context放在worker的结构体中,也会混淆两者的生命周期,用户甚至无法判断是否需要在new一个worker的时候顺便new一个新的context的实例,是否需要在此时设置超时时间。
推荐使用方式
因此go语言文档建议开发者将context作为函数的第一个入参。这种通过参数传递的方式,用户可以在每次调用的时候设置过期时间,cancel方法以及元数据。上下文如何传递给每个方法变得清晰,传递给一个方法的context不会被任何其他方法使用。因为context被限制为一个很小的范围,上下文的范围与它需要的操作一样小,这大大增 加了此包中上下文的实用性和清晰度。
总结
上下文可以轻松地将重要的跨库和跨服务信息传播,让一次请求的每个节点都了解一份信息。但是,它必须一致且清晰地使用,以保持可理解、易于调试和其有效性。