标签 TIOBE 下的文章

2023年Go语言盘点:稳中求新,稳中求变

本文永久链接 – https://tonybai.com/2023/12/31/the-2023-review-of-go-programming-language

时光荏苒,转眼间已经是2023年的最后一天了。《2022年Go语言盘点:泛型落地,无趣很好,稳定为王》仿佛就写在昨天。

回首这一年,全球彻底从新冠大流行中得以复苏,Go语言也不例外,最直观的表现就是全球各地的GopherCon技术大会或小型Meetup都纷纷从停办/线上的状态来到了线下,并获得Gopher们的热烈欢迎和踊跃参与,比如下图中的GopherConGopherCon UKGopherCon EuropeGopherCon AustraliaGolab等。

尤其值得一提的是我们本土最大的Gopher技术大会GopherChina 2023,今年为了满足不同地域Gopher的需求,GoCN社区在6月和11月分别在北京和上海举办了两次GopherChina大会,这也是历史首次。

Go语言团队的大神们也开始重新“乐此不疲”地参与到上述这些大会中,以推进全球Go社区与生态的建设。就连已经退居二线的Go语言之父Rob Pike也亲自“现身说法”,在年底的GopherCon Australia 2023上发表了“What We Got Right, What We Got Wrong”的主题演讲来回顾Go诞生以来的得与失。

大神回顾一生,我们盘点一年。在这篇文章中,我就和大家一起聊聊Go在2023年的状态、所处的位置以及Go未来演进的机制与策略。

1. Go的2023

1.1 稳

一如往年,Go在2023年发布了两个大版本,分别是2023年2月份的Go 1.20和8月份的Go 1.21

在这两个版本中,Go语法特性一如既往的求稳,除了支持切片类型到数组类型(或数组类型的指针)的类型转换,其余更是像语法的修修补补,比如:comparable“放宽”了对泛型实参的限制、unsafe包继续添加“语法糖”、增加min、max和clear预定义函数、增强type inference能力等。

这些并不会让Gopher感到“意外”,因为这与Russ Cox在2022年宣称的“Go is boring”的精神是一脉相承的。

不过,除了Go语法特性变化方面的“寡淡”之外,Go在其他方面还是求新和求变的,接下来我们先来看看Go是如何求新的。

注:求新与求变可能存在交集的地方,边界可能也有一定模糊性,也存在相互促进的情况,希望大家阅读下面内容时不要吹毛求疵:)。

1.2 求新

Go在语法特性求稳的同时,在编译器、工具链、运行时以及标准库等方面都在努力优化和打磨,旨在进一步提升Go兼具的生产力与运行时效率,其中很多优化和打磨的措施不乏新颖。

Go 1.20版本中首次引入的PGO(profile-guided optimization)技术预览版,到Go 1.21版本变为默认开启,Go官方给出的PGO优化的效果数据是:PGO优化带来的性能提升一般是2%~7%,而在最新的Go 1.22rc1中,这个数字已经变为2%~14%了。

在内存管理方面,Go 1.20引入了试验特性arena包,虽然它没能在Go 1.21中按时转正,如今处于proposal-hold状态,但这也算是一次在内存管理机制上的求新。

Go是一门面向软件工程的编程语言,在这一年中,Go在软件工程领域的求新例子也是不少。比如:可用于大幅简化Go项目创建的gonew工具,它支持基于go project template clone并创建一个属于你的Go项目;再比如对应用执行时的代码覆盖率的采集,可以帮助开发者更进一步了解最终可执行程序代码执行路径上的测试覆盖情况;而govulncheck工具则是Go在软件工程与供应链安全领域的求新尝试,该工具丰富了我们对Go项目进行安全漏洞检查的手段。

注:关于供应链安全问题,Russ Cox近期有一个专门的Talk:Open Source Supply Chain Security at Google,感兴趣的童鞋可以学习一下。

Go始终对IT界出现的新技术、新趋势以及Go社区的新想法保持open。在WASM出现早期,Go就提供了对wasm的porting支持,如今在Go 1.21中,Go还对尚未形成最终规范的WASI(WebAssembly System Interface)提供了支持。

Go社区的反馈也是Go团队求新的来源,比如一个典型例子就是log/slog加入标准库,让Go标准库原生支持了结构化日志输出,且日志性能不输像zap这样的第三方开源log包

Go社区也跟随Go团队的节奏,走在求新的道路上。2023年,IT界最大的事件就是以ChatGPT为代表的大语言模型的横空出世,这很可能是一个百年不遇的、对人类文明进步有着重要里程碑意义的事件。各行各业,言必称大模型,言必称AI。在传统机器学习、深度学习以及神经网络方面生态并不丰富的Go,也在尝试与大模型对接,比如:支持快速在本地启动和运行llama2、mistral 7B、codellama、vicuna等大模型的ollama开源项目在短短几个月就收获近30k个小星星的关注;再比如Gemini大模型推出后,Google一并开源了支持与Google各种大模型项目对接的Google AI Go SDK开源项目,并提供了详细的教程指导Gopher如何通过该SDK与大模型交互

注:Google把Gemini Pro的API免费提供给个人用户了,该模型具备GPT 3.5 级别的能力,32k 上下文,38 种语言支持以及多模态支持,唯一的约束是每分钟60个请求。

2023年第二次Go用户调查报告中,Go 开发者表示,他们对改善其编写代码的质量、可靠性和性能的人工智能/机器学习工具感兴趣,而不是编写代码的工具。一位时刻警醒、从不忙碌的专家“审阅者”可能是一种更有帮助的AI开发者辅助形式。Go官方表示了对该调查结果的重视,也许在后续的Go工具链中“AI加持”会成为常态。

1.3 求变

2023年8月,在Go 1.21版本刚刚发布后,Go官博就发布了Russ Cox编写的两篇文章:《Backward Compatibility, Go 1.21, and Go 2》和《Forward Compatibility and Toolchain Management in Go 1.21》,进一步明确了Go承诺的向后兼容的范围和方案,并第一次阐述了向前兼容性的具体方案,这两篇文章为Go语言后续的“求变”奠定了理论基础。

在向后兼容方面,从Go 1.21开始Russ Cox提出一些举措,比如:Go将扩展和规范化了GODEBUG的使用,其大致思路如下:

  • 对于每个在Go1兼容性承诺范围内的且可能会破坏(break)现有代码的新特性/新改变(比如:panic(nil)语义的改变)加入时,Go会向GODEBUG设置
    中添加一个新选项(比如GODEBUG=panicnil=1),以保留采用原语义进行编译的兼容能力;
  • GODEBUG中新增的选项将至少保留两年(4个Go release版本),对于一些影响重大的GODEBUG选项(比如http2client和http2server),保留的时间可能更长,甚至一直保留;
  • GODEBUG的选项设置与go.mod的go version是匹配的。例如,即便你现在的工具链是Go 1.21,如果go.mod中的go version为1.20,那么GODEBUG控制的新特性语义将不起作用,依旧保持Go 1.20时的行为。除非你将go.mod中的go version升级为go 1.21.0;
  • 在Go 1.21及以后版本中,除了可以使用像GODEBUG=panicnil=1的环境变量恢复原先语义外,还可以在main包中使用//go:debug指示符。

在向前兼容方面,Russ Cox提出的方案有些复杂难懂,这里就不赘述了,感兴趣的童鞋可以阅读一下我之前的文章《聊聊Go语言的向前兼容性和toolchain规则》了解更多细节。

1.3.1 语法填坑

在Go的诸多“求变”中,影响最大的还是对已有语法坑的“修正”,这些“填坑”工作或多或少都会对存量代码带去影响,甚至是break change,Go社区的反对声音也是不少。但无论怎样,这些工作已经在Go 1.21版本拉开帷幕了。比如:改变panic(nil)的语义以及对循环变量语义的变更,大家可以在《Go 1.21中值得关注的几个变化》一文中了解更多细节。

对现有语法坑的修正也进一步促进了“求新”,比如在修正loopvar语义的同时,for range支持对更多类型表达式的迭代也在进行中,比如Go 1.22中,for range将支持迭代整型表达式,并以试验特性提供了对函数迭代器的支持。

1.3.2 标准库v2示范

Go号称是“自带电池”的语言,其高质量的标准库得到了广大Gopher的欢迎。Go团队也一直努力推进Go标准库功能的丰富性,比如:Go 1.22中对http.ServeMux功能进行了增强,使其像第三方的gorilla/mux那样增加对带有通配符路由的匹配。

Go 1.22中,标准库还首次出现了v2版本包:math/rand/v2,这为后续标准库的vN方式演进提供了示范,从Go团队的官方issue、discussion中了解到,后续如sync/v2、encoding/json/v2等已经列上日程了。

2. Go所处的位置

很多人关注Go当前的状态:国内大厂用的多么?小厂是不是也在广泛采纳。这些问题我在往年的Go语言盘点时也都做过梳理,今年就不再提了。没有哪个大厂在广泛采用一门语言后,会在一年内全部推翻重写的;小厂对Go的采纳也是有惯性的。

今年先从我的两个意外“收获”开始。

2.1 两个意外的“收获”

2023年10月中旬,世界知名电动车厂商Tesla发布了新版fleet APIvehicle command SDK,鉴于本人也在智能网联汽车行业内打拼,于是对Tesla的此次发布做了一些深入了解。在Tesla的github主页上我赫然发现:Go是目前Tesla开源项目的第二大语言。

相对于传统的主机厂(车厂),Telsa算是比较开放的了。开放包含两个含义,一是将车端能力的开放,二是项目的开源。就目前了解到,国内主机厂还鲜有将车端能力开放出来的,开源就更是鲜见。但Tesla在这两方面都做到了,既开放了车端API,又做了针对性的开源,虽然目前其开源项目并不多。以前Tesla涉及到云端服务的项目多用Ruby,但从2022年开始,Go语言的使用逐渐增多,包括前面提到的Fleet API的Fleet Telemetry的参考server实现以及Tesla车辆远控SDK

我们再来看看Apache基金会。众所周知,Apache基金会的开源项目多以Java语言为主,但一次偶然的机会翻看Apache基金会的github项目主页,我发现Go语言在Apache开源项目中已经悄悄地跻身到第五名,如果仅算后端语言的话,Go排名第三,仅次于Java和Python。

并且,Apache基金会下面的Go项目实际也不少,大家可以通过https://github.com/orgs/apache/repositories?language=go&type=all查询。其中还不乏优秀之作,比如:构建Q&A知识系统的answerApache Dubbo的go实现dubbo-goCDN实现trafficcontrolKubernetes原生的轻量级企业应用集成框架Camel KApache Arrow的Go实现以及针对开发过程的聚合数据平台devlake等。

我们知道:Apache项目在企业级应用和平台方面具有广泛的应用,从Go语言在Apache基金会项目中的使用比例的提升现象来看,Go在企业应用市场中的普及度和受欢迎程度确实有所增长。

2.2 Go语言排名

编程语言之间的竞争与争议,通常被称为“编程语言战争”(programming language war),它其实反映了不同技术群体和范式之间的碰撞。这些“火药味”比较浓的语言之争通常比较主观。近10年来,业界出现了一些被广泛接受的编程语言排行榜,它们基于一些相对客观的数据来反映不同编程语言在现实开发中的真实状态。但不同编程语言排行榜都有不同的数据来源和数据模型,单一的排行榜往往是“盲人摸象”,无法反映全貌。但目前又没有一个可以让我们一窥全貌的权威排行榜。因此,要想更客观地、更全面的反映一门编程语言的实际情况,我们需要将多个排行榜参照着看。

下面我们就来看看在目前世界上著名的编程语言排行榜上,Go语言在其中的最新排名情况(请注意:各个榜单的发布时间不同,导致各榜单的数据会有一定时间差)。

2.2.1 PYPL编程语言排行榜

PYPL编程语言流行指数是通过分析语言教程在谷歌上的搜索频率而创建的。语言教程被搜索的次数越多,说明该语言越受欢迎,原始数据来自Google Trends:


PYPL编程语言排行榜,数据时间:2023.12

2.2.2 IEEE Spectrum排行榜

IEEE Spectrum排行榜是通过调查来自全球软件工程师和招聘网站的数据,统计各语言的流行度的:


IEEE Spectrum排行榜,数据时间:2023.8

2.2.3 RedMonk编程语言排行榜

RedMonk排行榜是根据GitHub和Stack Overflow这两个开发者社区上的讨论数量来推算语言的受关注度。


RedMonk编程语言排行榜,数据时间:2023.5

2.3.4 Github Octoverse

GitHub Octoverse排行榜直观反映了过去一年GitHub上各编程语言的实际使用和流行趋势,是从开源项目量的维度来衡量编程语言活跃度的。在Top 10语言榜单上,2023年Go超越Ruby第一次跻身Github Top10语言:


Github Octoverse编程语言排行榜,数据时间:2023.11


Github Octoverse编程语言排行榜,数据时间:2023.11

2.3.5 Github Language Stats(githut)

Github Language Stats是一个个人项目,它基于github公开数据,按时间、pr数量、star数量等维度对各个语言在github上的使用情况进行分析:


Githut按PR数量,数据时间:2023第三季度


Githut按Star数量,数据时间:2023第三季度

2.3.6 TIOBE编程语言排行榜

TIOBE编程语言排行榜理论上来说,是世界上最知名的编程语言排行榜,它根据各大搜索引擎编程语言相关的搜索查询量来计算一个综合指数。但这些年TIOBE榜单数据的“上蹿下跳”,让开发者对该榜单是“又爱又恨”。下面是TIOBE index 2023年12月份的榜单:

当你看到Fortran排在Go的前面,你就get到该榜单的抽风式的“不靠谱”了:)。

综合上述6个榜单,我们可以看到Go语言的2023基本处于稳定发展状态,没有“大踏步”的前进,也没有意想不到的大幅退步。

今年在国内某乎上总有一些有关“Go在国内是否已凉”的话题,从上面实际情况来看,话题中那些抹黑Go的观点可以不攻自破了。有人会说Rust的强势上升对Go会有一定冲击,这的确不可否认,就像Go当年火速蹿升给Java带去一定冲击一样,这是一门编程语言在演进阶段必会经历的过程,没有什么值得大惊小怪的。5年后,Rust可能同样也会受到来自其他语言的冲击。

Go语言未来会变得如何,关键还要看Go团队对Go未来演进方向的把握是否得当以及Go社区与生态是否给力。2023年,Go团队也明确了未来的演进机制和策略,接下来我们就来看看。

3. Go的未来演进

2023年是Go语言开源的第14个年头,Go语言早已蜕下了少年期的青涩,进入到了青年期。这意味着它拥有了越来越成熟稳定的语言特性,同时生态系统也日益丰富完善。作为一门青壮年语言,Go语言在系统设计方面展现出的高度工程化思想,使其轻松应对复杂系统的构建。以go module为主的模块化支持帮助大规模程序更加清晰化,丰富的并发控制手段使其可以处理海量请求。与此同时,Go语言生态也在蓬勃成长——各种高质量框架应运而生,无数module可复用,大量的云原生组件可供选择。这为开发者极大减轻了从零开始搭建系统的工作量。

和我们人类一样,一门语言进入青年期后的成熟特征并不能完全掩饰其未来演进的迷茫!在Ken Thompson、Rob Pike相继退休后,Russ Cox成为了Go这艘大船的“掌舵者”,Russ Cox与Go团队对编程语言的思考,对Go语言价值观的判断将直接决定Go未来的航向。

好在,在2023年的GopherCon大会上,我们得到了Russ Cox的答案:那就是基于共同目标和数据驱动的决策。这里借用Russ Cox在演讲中给出的结论来看看具体的演进驱动机制:

  • 首先,Go需要不断变化,特别是随着计算世界的变化。
  • 其次,任何改变的目标都是为了使Go在软件工程中变得更好,尤其是在规模化(scaling)方面。
  • 第三,一旦我们确定了目标,达成共识的下一个最重要的部分是拥有共享数据来做出决策。
  • 第四,Go工具链遥测是增补我们现有调查和代码分析数据的重要数据来源。

综上来看,Go团队要“拥抱变化”,但不能“无头苍蝇”一样的胡乱改变,而是严谨地基于广泛的数据反馈,包括来自用户调查、vscode插件运行的用户反馈、全年进行的研究访谈和用户体验研究等,以及来自即将加入Go工具链的可选遥测(opt-in Telemetry)功能获取到的更多真实的Go使用数据。

相信在Go工具链的可选遥测(opt-in Telemetry)功能加入后,Go团队能基于这些用户数据拿到更准确地决策依据,继续让Go这艘大船行驶在正确、光明的航向上!

4. 小结

在2023年,Go语言继续保持了其稳定性和可靠性的特点。发布了两个大版本,Go 1.20和Go 1.21,其中语法特性的改变相对较少,注重修复和优化。然而,Go语言在其他方面仍然保持着求新和求变的态势。

Go语言团队致力于优化编译器、工具链、运行时和标准库,以提升生产力和运行时效率。引入了一些新的特性和优化措施,例如PGO(profile-guided optimization)技术的引入和优化、内存管理方面的改进等。同时,Go语言在软件工程领域也进行了一些创新,如简化项目创建的gonew工具、代码覆盖率的采集工具、供应链安全领域的govulncheck工具等。

Go语言始终保持对新技术、新趋势和社区的开放姿态。在2023年,Go语言对WASM和WASI的支持得到了进一步加强。同时,Go社区也积极响应并跟随Go团队的步伐,面对IT界出现的大语言模型等新兴技术,Go社区也在不断探索和应用。

总体而言,2023年对于Go语言来说是一个稳中求新、稳中求变的年份。Go语言保持着其简洁、高效和易用的特点,同时积极适应和采纳新的技术和需求,为开发者提供更好的开发体验和工具支持。

展望未来,Go团队已经明确了更加以共识和用户数据为驱动的演进机制,保证Go的发展方向与实际需求保持同步。随着可选的工具链遥测功能加入,相信他们能基于更丰富的用户数据做出更正确、更具预见性的正确决策。

我个人依旧坚持我之前的判断:Go将进入或已处于自己的黄金5-10年


“Gopher部落”知识星球旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!2023年,Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码,关注代码质量并深入理解Go核心技术,并继续加强与星友的互动。欢迎大家加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻) – https://gopherdaily.tonybai.com

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite
  • Gopher Daily归档 – https://github.com/bigwhite/gopherdaily

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

Go 1.21新特性前瞻

本文永久链接 – https://tonybai.com/2023/04/26/go-1-21-foresight

Go 1.21版本正在如火如荼地开发当中,按照Go核心团队的一年两次的发布节奏来算,Go 1.21版本预计将在2023年8月发布(Go 1.20版本是在2023年2月份发布的)。

本文将和大家一起看看Go 1.21都会带来哪些新特性。不过由于目前为时尚早,下面列出的有些变化最终不一定能进入到Go 1.21的最终版本中,所以切记一切变更要以最终Go 1.21版本发布时为准。

在细数变化之前,我们先来看看Go语言的当前状态。

1. Go语言当前状态

《2022年Go语言盘点》一文中,我们提到年初Go语言的2022年终排名为12位,同时TIOBE官方编辑也提到:“在新兴编程语言中,Go是唯一一个可能在未来冲入前十的后端编程语言”。Go语言的发展似乎应验了这一预测,在今年的3月份,Go就再次进入编程语言排行榜前十:

一个月后的四月初,TIOBE排行榜上,Go稳住了第10名的位次:

在国内,在鹅厂前不久发布的《2022年腾讯研发大数据报告》中,

在国内,继Go在2021年从C++手中夺过红旗首次登顶鹅厂最热门编程语言之后,在鹅厂前不久发布的《2022年腾讯研发大数据报告》中,Go蝉联鹅厂最热门编程语言,继续夯实在国内头部互联网公司内的优势地位:

Go于2009年开源,在经历多年的宣传和鼓吹后,Go目前进入了平稳发展的阶段。疫情结束后,原先线上举办或取消的国内外的Go技术大会现在陆续又都开始恢复了,相信这会让更多开发人员接触到Go。像Go这样的能在世界各地持续多年举办技术大会的语言真是不多了。

接下来,我们就来聚焦到Go 1.21版本,挖掘一下这个版本都有哪些新特性。

2. 语言变化

目前Go 1.21版本里程碑中涉及语言变化的有大约2项,我们来看看。

2.1 增加clear预定义函数

Go 1.21增加了一个clear预定义函数用来做切片和map的clear操作,其原型如下:

// $GOROOT/src/builtin.go

// The clear built-in function clears maps and slices.
// For maps, clear deletes all entries, resulting in an empty map.
// For slices, clear sets all elements up to the length of the slice
// to the zero value of the respective element type. If the argument
// type is a type parameter, the type parameter's type set must
// contain only map or slice types, and clear performs the operation
// implied by the type argument.
func clear[T ~[]Type | ~map[Type]Type1](t T)

clear是针对map和slice的操作函数,它的语义是什么呢?我们通过一个例子来看一下:

package main

import "fmt"

func main() {
    var sl = []int{1, 2, 3, 4, 5, 6}
    fmt.Printf("before clear, sl=%v, len(sl)=%d, cap(sl)=%d\n", sl, len(sl), cap(sl))
    clear(sl)
    fmt.Printf("after clear, sl=%v, len(sl)=%d, cap(sl)=%d\n", sl, len(sl), cap(sl))

    var m = map[string]int{
        "tony": 13,
        "tom":  14,
        "amy":  15,
    }
    fmt.Printf("before clear, m=%v, len(m)=%d\n", m, len(m))
    clear(m)
    fmt.Printf("after clear, m=%v, len(m)=%d\n", m, len(m))
}

运行该程序:

before clear, sl=[1 2 3 4 5 6], len(sl)=6, cap(sl)=6
after clear, sl=[0 0 0 0 0 0], len(sl)=6, cap(sl)=6
before clear, m=map[amy:15 tom:14 tony:13], len(m)=3
after clear, m=map[], len(m)=0

我们看到:

  • 针对slice,clear保持slice的长度和容量,但将所有slice内已存在的元素(len个)都置为元素类型的零值;
  • 针对map,clear则是清空所有map的键值对,clear后,我们将得到一个empty map。

2.2 改变panic(nil)语义

使用defer+recover捕获panic是Go语言唯一处理panic的方法,其典型模式如下:

package main

import "fmt"

func foo() {
    defer func() {
        if err := recover(); err != nil {
            fmt.Printf("panicked: %v\n", err)
            return
        }
        fmt.Println("it's ok")
    }()

    panic("some error")
}

func main() {
    foo()
}

运行上面程序会输出:

panicked: some error

例子中我们向panic传入了表示panic原因的字符串,panic的参数是一个interface{}类型,可以传入任意值,当然也可以传入nil

比如上面例子,当我们给foo函数的panic调用传入nil时,我们将得到下面结果:

it's ok

这可能会给开发者带去疑惑:明明是触发了panic,但函数却按照正常逻辑处理!2018年,前Go核心团队成员bradfitz就提出了一个issue:spec: guarantee non-nil return value from recover,提出当开发者调用panic(nil)时,recover应该返回某种runtime error,而不是nil。这个issue在今年被纳入了Go 1.21版本,现在该issue的实现已经被merge到了主干。

新的实现在src/runtime/panic.go中定义了一个名为PanicNilError的新Error:

// $GOROOT/src/runtime/panic.go

// A PanicNilError happens when code calls panic(nil).
//
// Before Go 1.21, programs that called panic(nil) observed recover returning nil.
// Starting in Go 1.21, programs that call panic(nil) observe recover returning a *PanicNilError.
// Programs can change back to the old behavior by setting GODEBUG=panicnil=1.
type PanicNilError struct {
    // This field makes PanicNilError structurally different from
    // any other struct in this package, and the _ makes it different
    // from any struct in other packages too.
    // This avoids any accidental conversions being possible
    // between this struct and some other struct sharing the same fields,
    // like happened in go.dev/issue/56603.
    _ [0]*PanicNilError
}

func (*PanicNilError) Error() string { return "panic called with nil argument" }
func (*PanicNilError) RuntimeError() {}

Go编译器会将panic(nil)替换为panic(new(runtime.PanicNilError)),这样我们用Go 1.21版本运行上面的程序,我们就会得到下面结果了:

panicked: panic called with nil argument

如果你的遗留代码中调用了panic(nil)(注:显然这不是一种很idiomatic的作法),升级到Go 1.21版本后你就要小心了。如果你想保留原先的panic(nil)行为,可以用GODEBUG=panicnil=1。

有童鞋可能会质疑这违反了Go1兼容性承诺,但实际上Go1兼容性规范保留了对语言规范中不一致或错误的修订权力,即便这种修订会导致遗留代码出现与原先不一致的行为。

3. 编译器与工具链

每个Go版本中,编译器和工具链的改动都不少,我们挑重点看一下:

3.1 一些OS的最小支持版本的更新

Go 1.21开始,go installer支持最小macOS版本更新为10.15,而最小Windows版本为Windows 10

3.2 低版本的go编译器将拒绝编译高版本的go module

从Go 1.21版本开始,低版本的go编译器将拒绝编译高版本的go module(go.mod中go version标识最低版本) ,这也是Russ Cox策划的Go扩展的向前兼容性提案的一部分。此外,Go扩展向前兼容性提案感觉比较复杂,可能不会全部在Go 1.21版本落地。

3.3 支持WASI

Go从1.11版本就开始支持将Go源码编译为wasm二进制文件,并在支持wasm的浏览器环境中运行。

不过WebAssembly绝不仅仅被设计为仅限于在Web浏览器中运行,核心的WebAssembly语言是独立于其周围环境的,WebAssembly完全可以通过API与外部世界互动。在Web上,它自然使用浏览器提供的现有Web API。然而,在浏览器之外,之前还没有一套标准的API可以让WebAssembly程序使用。这使得创建真正可移植的非Web WebAssembly程序变得困难。WebAssembly System Interface(WASI)是一个填补这一空白的倡议,它有一套干净的API,可以由多个引擎在多个平台上实现,并且不依赖于浏览器的功能(尽管它们仍然可以在浏览器中运行)。

Go 1.21将增加对WASI的支持,初期先支持WASI Preview1版本,之后会支持WASI Preview2版本,直至最终WASI API版本发布!目前我们可以使用GOOS=wasip1 GOARCH=wasm将Go源码编译为支持WASI的wasm程序,下面是一个例子:

// main.go
package main            

func main() {
    println("hello")
}

下载最新go dev版本后(go install http://golang.org/dl/gotip@latest),可以执行下面命令将main.go编译为wasm程序:

$ GOARCH=wasm GOOS=wasip1 gotip build -o main.wasm main.go

开源的wasm运行时有很多,wazero是目前比较火的且使用纯Go实现的wasm运行时程序,安装wazero后,可以用来执行上面编译出来的main.wasm:

$curl https://wazero.io/install.sh
$wazero run main.wasm
hello

3.4 Go 1.21可能推出纯静态工具链,不再依赖glibc

使用纯Go实现的net resolver,原先DNS的问题也将被解决,这样Go团队很可能在构建工具链的时候使用CGO_ENABLED=0构建出静态工具链,没有动态链接库的依赖。

3.5 go test -c支持为多个包同时构建测试二进制程序

Go 1.21版本之前,go test -c仅支持将单个包的测试代码编译为测试二进制程序,Go 1.21版本则允许我们同时为多个包构建测试二进制程序

下面是官方给出的例子:

$ go test -c -o /tmp ./pkg1 ./pkg2 ./pkg2
$ ls /tmp
pkg1.test pkg2.test pkg3.test

3.6 增加\$GOROOT/go.env

今天使用go env -w命令修改的默认环境变量会写入:filepath.Join(os.UserConfigDir(), “go/env”)。在Mac上,这个路径是\$HOME/Library/Application Support/go/env;在Linux上,这个路径是\$HOME/.config/go/env。

Go 1.21将增加一个全局层次上的go.env,放在\$GOROOT下面,目前默认的go.env为:

// $GOROOT/go.env

# This file contains the initial defaults for go command configuration.
# Values set by 'go env -w' and written to the user's go/env file override these.
# The environment overrides everything else.

# Use the Go module mirror and checksum database by default.
# See https://proxy.golang.org for details.
GOPROXY=https://proxy.golang.org,direct
GOSUMDB=sum.golang.org

我们仍然可以通过go env -w命令修改user级的env文件来覆盖上述配置,当然最高优先级的是OS用户环境变量,如果在OS用户环境变量文件(比如.bash_profile、.bashrc)中设置了Go的环境变量值,比如GOPROXY等,那么以OS用户环境变量为优先。

4. 标准库

我们接下来再来看看变更最多的一部分:标准库,我们将对主要变更项作简要介绍。

4.1 slices和maps进入标准库

Go 1.18版本泛型落地发布前的最后一刻,Rob Pike叫停了slices、maps等泛型包的入库,后来这两个包先放置在golang.org/x/exp下作为实验包。随着Go泛型日益成熟以及Go团队对泛型使用经验的增多,Go团队终于决定将golang.org/x/exp/slicesgolang.org/x/exp/maps在Go 1.21版本中将挪入标准库。

4.2 log/slog加入标准库

log/slog是Go官方版结构化日志包,大致与uber的zap包相当。在我之前的一篇文章《slog:Go官方版结构化日志包》有对slog的详尽说明,大家可以移步到那篇文章看看。不过slog的proposal依旧很多,后续slog可能会有持续改进和变更,与那篇文章中的内容可能会有一些差异。

4.3 sync包增加OnceFunc、OnceValue和OnceValues

在sync.Once的基础上,这个issue增加了三个与Once相关的”语法糖”API,用在一些对Once有需求的最常见的场景中。

4.4 增加testing.Testing函数

Go 1.21为testing包增加了func Testing() bool函数,该函数可以用来报告当前程序是否是go test创建的测试程序。使用Testing函数,我们可以确保一些无需在单测阶段执行的函数不被执行。比如下面例子来自这个issue:

// file/that/should/not/be/used/from/testing.go

func prodEnvironmentData() *Environment {
    if testing.Testing() {
        log.Fatal("Using production data in unit tests")
    }
    ....
}

4.5 一些变更点

5. 参考资料


“Gopher部落”知识星球旨在打造一个精品Go学习和进阶社群!高品质首发Go技术文章,“三天”首发阅读权,每年两期Go语言发展现状分析,每天提前1小时阅读到新鲜的Gopher日报,网课、技术专栏、图书内容前瞻,六小时内必答保证等满足你关于Go语言生态的所有需求!2023年,Gopher部落将进一步聚焦于如何编写雅、地道、可读、可测试的Go代码,关注代码质量并深入理解Go核心技术,并继续加强与星友的互动。欢迎大家加入!

img{512x368}
img{512x368}

img{512x368}
img{512x368}

著名云主机服务厂商DigitalOcean发布最新的主机计划,入门级Droplet配置升级为:1 core CPU、1G内存、25G高速SSD,价格5$/月。有使用DigitalOcean需求的朋友,可以打开这个链接地址:https://m.do.co/c/bff6eed92687 开启你的DO主机之路。

Gopher Daily(Gopher每日新闻)归档仓库 – https://github.com/bigwhite/gopherdaily

我的联系方式:

  • 微博(暂不可用):https://weibo.com/bigwhite20xx
  • 微博2:https://weibo.com/u/6484441286
  • 博客:tonybai.com
  • github: https://github.com/bigwhite

商务合作方式:撰稿、出书、培训、在线课程、合伙创业、咨询、广告合作。

如发现本站页面被黑,比如:挂载广告、挖矿等恶意代码,请朋友们及时联系我。十分感谢! Go语言第一课 Go语言精进之路1 Go语言精进之路2 商务合作请联系bigwhite.cn AT aliyun.com

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn
DigitalOcean Referral Badge

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats