Go:文章Contexts and structs(二)

111 阅读2分钟

「这是我参与2022首次更文挑战的第5天,活动详情查看:2022首次更文挑战」。

(*Worker).Fetch 和 (*Worker).Process 方法都使用存储在 Worker 中的context。 这可以防止 Fetch 和 Process 的调用者(它们本身可能有不同的上下文)指定截止日期、请求取消以及在每个调用的基础上附加元数据。 例如:用户无法为 (*Worker).Fetch 提供截止日期,或仅取消 (*Worker).Process 调用。 调用者的生命周期与共享上下文混合在一起,并且上下文的范围是创建 Worker 的生命周期。

与 通过参数传递 的方法相比,通过结构体参数来传递更容易让用户感到困惑。 用户可能会问自己:

  • 由于 New一个Worker 需要指定一个 context.Context,那么构造函数是否在做需要取消调用或设置截止日期的工作?
  • 对于 context是否能够在(*Worker).Fetch 和 (*Worker).Process方法中使用? 是两者都不行? 还是一个可以但是另一个不可以?

API 需要大量文档来明确告诉用户 context.Context 的用途。 甚至用户可能还必须阅读代码,而不是能够依赖 API 文档能够完全理解。

最后,如果设计一个生产级服务器,它的每个请求都没有上下文,无法设置每次调用的最后期限,您的进程可能会积压并耗尽其资源(如内存)!

规则的例外:保持向后兼容性

当引入 context.Context 的 Go 1.7 发布时,大量 API 必须以向后兼容的方式添加上下文支持。 例如,net/http 的 Client 方法,如 Get 和 Do,是上下文的绝佳候选者。 使用这些方法发送的每个外部请求都将受益于 context.Context 附带的截止日期、取消和元数据支持。

有两种方法可以向后兼容的方式添加对 context.Context 的支持:在结构中包含上下文,我们稍后会看到,以及复制函数,副本接受 context.Context 并将 Context 作为其函数名后缀 . 复制方法应优先于 context-in-struct(在结构中包含上下文),并在保持模块兼容中进一步讨论。 但是,在某些情况下它是不切实际的:例如,如果您的 API 公开了大量函数,那么将它们全部复制可能是不可行的。