2021年2月24日 Go生态洞察:Contexts和Structs的深度解析


🌷🍁 博主猫头虎(🐅🐾)带您 Go to New World✨🍁

🦄 博客首页——🐅🐾猫头虎的博客🎐
🐳 《面试题大全专栏》 🦕 文章图文并茂🦖生动形象🐅简单易学!欢迎大家来踩踩~🌺
🌊 《IDEA开发秘籍专栏》 🐾 学会IDEA常用操作,工作效率翻倍~💐
🌊 《100天精通Golang(基础入门篇)》 🐅 学会Golang语言,畅玩云原生,走遍大小厂~💐

🐅🐾猫头虎建议Go程序员必备技术栈一览表📖:

☁️🐳 Go语言开发者必备技术栈☸️:
🐹 GoLang | 🌿 Git | 🐳 Docker | ☸️ Kubernetes | 🔧 CI/CD | ✅ Testing | 💾 SQL/NoSQL | 📡 gRPC | ☁️ Cloud | 📊 Prometheus | 📚 ELK Stack


🪁🍁 希望本文能够给您带来一定的帮助🌸文章粗浅,敬请批评指正!🐅🐾🍁🐥


在这里插入图片描述

文章目录

    • 🐅🐾猫头虎建议Go程序员必备技术栈一览表📖:
  • 2021年2月24日 Go生态洞察:Contexts和Structs的深度解析 🌍
    • 摘要
    • 引言
    • 正文内容
      • 优先将contexts作为参数传递 📌
      • 在结构体中存储context会导致混淆 🚫
      • 规则的例外:保持向后兼容性
    • 总结
  • 原创声明

  • 原创作者: 猫头虎

  • 作者wx: Libin9iOak

  • 作者公众号: 猫头虎技术团队

在这里插入图片描述

2021年2月24日 Go生态洞察:Contexts和Structs的深度解析 🌍

摘要

🐆 猫头虎博主在此!今天我们要深入探讨Go语言中的一个重要话题:Contexts和Structs。这篇文章将深入探讨context.Context的正确使用方法,特别是在API设计中如何合理地运用。对于那些在互联网深处搜索“Go语言最佳实践”、“Contexts使用指南”或者“高效API设计”等词条的开发者们,这篇文章将是你的福音!

引言

在许多现代Go API中,函数和方法的第一个参数经常是context.Context。Context提供了一种在API边界和进程间传递截止日期、调用者取消以及其他请求范围值的手段。当库直接或间接地与远程服务器(如数据库、API等)交互时,通常会使用它。

根据Context的官方文档,建议不要在结构体类型中存储Context,而应将其传递给每个需要它的函数。本文将详细解释这一建议的原因,并提供例子说明为什么将Context作为参数传递比存储在其他类型中更为重要。

正文内容

优先将contexts作为参数传递 📌

要理解为什么不在结构体中存储context,让我们考虑首选的context-as-argument方法:

// Worker从远程作业编排服务器获取并添加作业。
type Worker struct { /* … */ }type Work struct { /* … */ }func New() *Worker {return &Worker{}
}func (w *Worker) Fetch(ctx context.Context) (*Work, error) {_ = ctx // A per-call ctx is used for cancellation, deadlines, and metadata.
}func (w *Worker) Process(ctx context.Context, work *Work) error {_ = ctx // A per-call ctx is used for cancellation, deadlines, and metadata.
}

这里,(*Worker).Fetch(*Worker).Process方法都直接接受一个context。通过这种传递参数的设计,用户可以设置每次调用的截止日期、取消和元数据。并且,传递给每个方法的context.Context的用途非常清晰:不期望一个方法中使用的context.Context会被其他方法使用。这是因为context的范围尽可能地缩小到所需的操作,这极大地提高了该包中context的实用性和清晰度。

在结构体中存储context会导致混淆 🚫

再次检查上面的Worker示例,但这次使用不推荐的context-in-struct方法。当你在结构体中存储context时,问题在于你将生命周期对调用者隐藏起来,或者更糟糕的是,以不可预测的方式将两个作用域混合在一起:

type Worker struct {ctx context.Context
}func New(ctx context.Context) *Worker {return &Worker{ctx: ctx}
}func (w *Worker) Fetch() (*Work, error) {_ = w.ctx // A shared w.ctx is used for cancellation, deadlines, and metadata.
}func (w *Worker) Process(work *Work) error {_ = w.ctx // A shared w.ctx is used for cancellation, deadlines, and metadata.
}

(*Worker).Fetch(*Worker).Process方法都使用存储在Worker中的context。这阻止了Fetch和Process的调用者(可能本身具有不同的contexts)为每次调用指定截止日期、请求取消和附加元数据。例如:用户无法仅为(*Worker).Fetch设置截止日期,或仅取消`(*Worker

).Process调用。调用者的生命周期与共享的context交织在一起,而context的范围限定在创建Worker`的生命周期内。

与传递参数方法相比,这种API对用户来说也更加令人困惑。用户可能会问自己:

  • 既然New接受一个context.Context,那么构造函数是否正在执行需要取消或有截止日期的工作?
  • 传递给Newcontext.Context是否适用于(*Worker).Fetch(*Worker).Process中的工作?都不是?一个而不是另一个?

API需要大量文档明确告诉用户context.Context的确切用途。用户可能还需要阅读代码,而不是依赖于API结构所传达的内容。

最后,设计一个每个请求都没有context、因此无法充分尊重取消请求的生产级服务器可能相当危险。如果没有设置每次调用的截止日期,你的进程可能会积压并耗尽其资源(如内存)!

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

当Go 1.7(引入了context.Context)发布时,大量API不得不以向后兼容的方式添加context支持。例如,net/httpClient方法,如GetDo,是context的理想候选者。使用这些方法发送的每个外部请求都将受益于随context.Context而来的截止日期、取消和元数据支持。

为了以向后兼容的方式支持context.Context,有两种方法:在结构体中包含context(如我们马上会看到的),以及复制函数,其中复制的函数接受context.Context并在其函数名称后缀中带有Context。应优先选择复制函数方法而不是context-in-struct方法,这在Keeping your modules compatible中有进一步讨论。然而,在某些情况下,这可能是不切实际的:例如,如果你的API暴露了大量函数,那么全部复制它们可能是不可行的。

net/http包选择了context-in-struct方法,这提供了一个有用的案例研究。让我们看看net/httpDo。在引入context.Context之前,Do的定义如下:

// Do发送一个HTTP请求并返回一个HTTP响应[...]
func (c *Client) Do(req *Request) (*Response, error)

在Go 1.7之后,如果不是为了保持向后兼容性,Do可能看起来如下所示:

// Do发送一个HTTP请求并返回一个HTTP响应[...]
func (c *Client) Do(ctx context.Context, req *Request) (*Response, error)

但是,保持标准库的向后兼容性并遵守Go 1兼容性承诺至关重要。因此,维护者选择在http.Request结构体中添加context.Context,以支持context.Context而不破坏向后兼容性:

// Request代表一个由服务器接收或客户端发送的HTTP请求。
// ...
type Request struct {ctx context.Context// ...
}// NewRequestWithContext返回一个新的Request,给定方法、URL和可选的
// body。
// [...]
// 给定的ctx用于Request的生命周期。
func NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*Request, error) {// 为了本文的简洁性进行了简化。return &Request{ctx: ctx,// ...}
}// Do发送一个HTTP

总结

使用context时,我们应该将其作为方法的第一个参数传递,而不是存储在struct类型中。这样,用户

可以充分利用它的扩展性,通过调用栈构建一个强大的取消、截止和元数据信息树。并且,当它作为参数传入时,它的作用域是清晰可见的,这导致了整个栈的清晰理解和可调试性。

知识要点总结表格:

关键点描述
Context作为参数提高了可读性和灵活性
避免在Structs中存储Context防止生命周期和作用域混淆
向后兼容性在必要时,可以在struct中添加Context

本文被猫头虎的Go生态洞察专栏收录,详情点击这里。

下一篇预告:
下次我们将探讨2020年Go开发者调查的结果,深入了解Go社区的趋势和见解!🚀📊

在这里插入图片描述

原创声明

======= ·

  • 原创作者: 猫头虎

  • 作者wx: Libin9iOak
    在这里插入图片描述

  • 作者公众号: 猫头虎技术团队

在这里插入图片描述

学习复习Go生态

本文为原创文章,版权归作者所有。未经许可,禁止转载、复制或引用。

作者保证信息真实可靠,但不对准确性和完整性承担责任

未经许可,禁止商业用途。

如有疑问或建议,请联系作者。

感谢您的支持与尊重。

点击下方名片,加入IT技术核心学习团队。一起探索科技的未来,洞察Go生态,共同成长。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/231250.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

输入通道数 和 输出通道数 的理解

输入通道数(in_channels)输出通道数(out_channels) 在卷积神经网络中通常需要输入 in_channels 和 out_channels ,即输入通道数和输出通道数,它们代表什么意思呢? 输入通道数(in_c…

Linux中tar命令的几个高级用法

在Linux世界中,Tar命令是一把解密归档世界的魔法工具。无论是打包、压缩还是解压,Tar命令都能胜任。本文将生动地介绍Tar命令的基本用法,并深入探讨五个常用选项,帮助读者在Linux系统中灵活运用这个强大的工具。 一、命令概述 Ta…

【刷题】动态规划

动态规划 139. 单词拆分(一维) 给你一个字符串 s 和一个字符串列表 wordDict 作为字典。请你判断是否可以利用字典中出现的单词拼接出 s 。 注意:不要求字典中出现的单词全部都使用,并且字典中的单词可以重复使用。 示例 1&…

Stable Diffusion绘画系列【6】:东方美学作品

《博主简介》 小伙伴们好,我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源,可关注公-仲-hao:【阿旭算法与机器学习】,共同学习交流~ 👍感谢小伙伴们点赞、关注! 《------往期经典推荐--…

智能优化算法应用:基于哈里斯鹰算法无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用:基于哈里斯鹰算法无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于哈里斯鹰算法无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.哈里斯鹰算法4.实验参数设定5.算法结果6.参考…

在PyCharm中配置PyQt5环境

在PyCharm中配置PyQt5环境 文章目录 1.安装第三方库2.PyQt5设计器3.PyUIC转换工具 🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ🌹꧔ꦿ&#x1…

网站域名那些事儿

互联网用户对于在线数据安全的意识逐渐增强,因此拥有一个可靠的网络安全系统是至关重要的。而其中一个最重要的元素就是网站域名SSL证书。 SSL(Secure Socket Layer)是一种用于确保网站与访客之间通信安全的技术。通过使用SSL证书&#xff0c…

Linux 基本语句_13_消息队列

概念: 不同进程能通过消息队列来进行通信,不同进程也能获取或发送特定类型的消息,即选择性的收发消息。 一般一个程序采取子进程发消息,父进程收消息的模式 常用函数功能: fork(); // 创建子进程 struct msgbuf{ …

【算法心得】When data range not large, try Bucket sort

https://leetcode.com/problems/maximum-number-of-coins-you-can-get/description/?envTypedaily-question&envId2023-11-24 I solve this problem by sorting piles first, and choose piles for(let i1;i<(piles.length/3)*2;i2) but: o(≧口≦)o Problem must …

开放式耳机怎么选?自费千元测评,百元、千元价位选哪个

开放式耳机以其不入耳式设计&#xff0c;更容易带给用户舒适的佩戴体验&#xff0c;也不影响使用中聆听周围声响&#xff0c;还可以保证长时间的舒适佩戴&#xff0c;适配漫长的通勤、游玩旅程。当然&#xff0c;开放式耳机种类也有许多&#xff0c;究竟哪一款更适合大家呢&…

智慧博物馆视频监控系统设计,可视化AI智能分析技术助力博物馆多维度监管

一、背景与需求 博物馆视频智能监控系统是智慧博物馆建设的重要组成部分&#xff0c;传统的博物馆视频监控系统以模拟系统架构为主&#xff0c;存在监管效率低、各个系统独立运作形成数据孤岛、以“事后补救”为主要监管手段等管理弊病&#xff0c;无法满足互联网高速发展背景…

kafka C++实现生产者

文章目录 1 Kafka 生产者的逻辑2 Kafka 的C API2.1 RdKafka::Conf2.2 RdKafka::Message2.3 RdKafka::DeliveryReportCb2.4 RdKafka::Event2.5 RdKafka::EventCb2.6 RdKafka::PartitionerCb2.7 RdKafka::Topic2.8 RdKafka::Producer&#xff08;核心&#xff09; 3 Kafka 生产者…