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

2023-11-29 19:04

本文主要是介绍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生态,共同成长。

这篇关于2021年2月24日 Go生态洞察:Contexts和Structs的深度解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/433960

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

从去中心化到智能化:Web3如何与AI共同塑造数字生态

在数字时代的演进中,Web3和人工智能(AI)正成为塑造未来互联网的两大核心力量。Web3的去中心化理念与AI的智能化技术,正相互交织,共同推动数字生态的变革。本文将探讨Web3与AI的融合如何改变数字世界,并展望这一新兴组合如何重塑我们的在线体验。 Web3的去中心化愿景 Web3代表了互联网的第三代发展,它基于去中心化的区块链技术,旨在创建一个开放、透明且用户主导的数字生态。不同于传统

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

基于UE5和ROS2的激光雷达+深度RGBD相机小车的仿真指南(五):Blender锥桶建模

前言 本系列教程旨在使用UE5配置一个具备激光雷达+深度摄像机的仿真小车,并使用通过跨平台的方式进行ROS2和UE5仿真的通讯,达到小车自主导航的目的。本教程默认有ROS2导航及其gazebo仿真相关方面基础,Nav2相关的学习教程可以参考本人的其他博客Nav2代价地图实现和原理–Nav2源码解读之CostMap2D(上)-CSDN博客往期教程: 第一期:基于UE5和ROS2的激光雷达+深度RG

韦季李输入法_输入法和鼠标的深度融合

在数字化输入的新纪元,传统键盘输入方式正悄然进化。以往,面对实体键盘,我们常需目光游离于屏幕与键盘之间,以确认指尖下的精准位置。而屏幕键盘虽直观可见,却常因占据屏幕空间,迫使我们在操作与视野间做出妥协,频繁调整布局以兼顾输入与界面浏览。 幸而,韦季李输入法的横空出世,彻底颠覆了这一现状。它不仅对输入界面进行了革命性的重构,更巧妙地将鼠标这一传统外设融入其中,开创了一种前所未有的交互体验。 想象

Go Playground 在线编程环境

For all examples in this and the next chapter, we will use Go Playground. Go Playground represents a web service that can run programs written in Go. It can be opened in a web browser using the follow

OWASP十大安全漏洞解析

OWASP(开放式Web应用程序安全项目)发布的“十大安全漏洞”列表是Web应用程序安全领域的权威指南,它总结了Web应用程序中最常见、最危险的安全隐患。以下是对OWASP十大安全漏洞的详细解析: 1. 注入漏洞(Injection) 描述:攻击者通过在应用程序的输入数据中插入恶意代码,从而控制应用程序的行为。常见的注入类型包括SQL注入、OS命令注入、LDAP注入等。 影响:可能导致数据泄

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

CSP 2023 提高级第一轮 CSP-S 2023初试题 完善程序第二题解析 未完

一、题目阅读 (最大值之和)给定整数序列 a0,⋯,an−1,求该序列所有非空连续子序列的最大值之和。上述参数满足 1≤n≤105 和 1≤ai≤108。 一个序列的非空连续子序列可以用两个下标 ll 和 rr(其中0≤l≤r<n0≤l≤r<n)表示,对应的序列为 al,al+1,⋯,ar​。两个非空连续子序列不同,当且仅当下标不同。 例如,当原序列为 [1,2,1,2] 时,要计算子序列 [