Go1.21.0 到 Go1.23.0 的改动,向前兼容性和toolchain规则,Go1.21.0,必须升级你的Go啦

Go各版本Release Note

Go1.21.0

2023-08-08

https://go.dev/doc/go1.21

内置方法

min & max:返回一个序列中的最大值最小值。

https://go.dev/ref/spec#Min_and_max

clear:清空map和slice。

https://go.dev/ref/spec#Clear

标准库

log/slog

The new log/slog package provides structured logging with levels. Structured logging emits key-value pairs to enable fast, accurate processing of large amounts of log data. The package supports integration with popular log analysis tools and services.

testing/slogtest

The new testing/slogtest package can help to validate slog.Handler implementations.

slices

The new slices package provides many common operations on slices, using generic functions that work with slices of any element type.

maps

The new maps package provides several common operations on maps, using generic functions that work with maps of any key or element type.

cmp

The new cmp package defines the type constraint Ordered and two new generic functions Less and Compare that are useful with ordered types.

toolchain

Go工具链管理,以及Go版本匹配规则。下文说到。

Go1.22

2024-02-06

1、修复 for 循环变量的错误

在此之前的写法

func main() {for i := 0; i < 5; i++ {v := iwg.Add(1)go func() {defer wg.Done()fmt.Println(v)}()}wg.Wait()
}

现在的写法

func main() {for i := 0; i < 5; i++ {wg.Add(1)go func() {defer wg.Done()fmt.Println(i)}()}wg.Wait()
}

2、range可以遍历整数

for i := range 10 {fmt.Println(10 - i)
}

3、标准库

math/rand/v2

https://go.dev/pkg/math/rand/v2/

go/version

The new go/version package implements functions for validating and comparing Go version strings.

Go1.23

2024-08-13

for-range 循环中的范围表达式现在可以是迭代器函数,例如 func(func(K) bool),这支持了用户对任意序列自定义迭代器。同时,slices 和 maps 包新增了一些与迭代器配合使用的功能,还新增了一个 iter 包。比如可以轻松地将 map 的键收集到切片中并对其值进行排序。

Range Over Function Types

标准库

1、对 time.Timer 和 time.Ticker 做了重大改动,与老的写法不兼容,鉴于Go的工具链管理,升级之后并不会对之前的项目构成影响,前提是你依旧按照原先的版本编译。

https://go.dev/doc/go1.23#library

首先,程序不再引用的计时器和 Tickers 立即有资格使用垃圾回收机制,即使它们的 Stop 方法没有被调用。早期版本的 Go 直到发射后才收集未停止的计时器,并且从未收集未停止的 Tickers。

其次,与 Timer 或 Ticker 关联的计时器通道现在是无缓冲的,容量为 0。此更改的主要效果是 Go 现在保证对于对 Reset 或 Stop 方法的任何调用,不会在调用后发送或接收在该调用之前准备的陈旧值。Go 的早期版本使用带有单元素缓冲区的通道,因此很难正确使用 Reset 和 Stop。此更改的一个明显效果是计时器通道的 len 和 Cap 现在返回 0 而不是 1,这可能会影响轮询长度以决定计时器通道上的接收是否会成功的程序。此类代码应使用非阻塞接收代替。

特别说明,当你的go.mod的go行大宇等于1.23.0,此项特性才会生效。当你用Go1.23编译老代码时,此特性不会生效。

2、增加了 unique 包

3、Iterators包

4、structs包

The new structs package provides types for struct fields that modify properties of the containing struct type such as memory layout.

向前兼容性

在以前的版本中,Go 工具链尝试编译依赖于新版本的代码时,可能会遇到兼容性问题。例如,如果你的代码依赖于 Go 1.18 引入的新特性,使用小于这个本本版本的 Go 编译器将会导致编译错误。但是,这些错误信息有时并不直观,可能仅仅显示为语法错误,而实际上是由于工具链版本不匹配。

在 Go 1.21 中,工具链会严格遵循 go.mod 文件中的版本声明。例如,如果你的 go.mod 文件中声明了 go 1.21.1,那么 Go 1.21.0 将无法编译这段代码。这种方式有效地避免了潜在的编译错误。

工具链管理

为了减少强制版本匹配对开发者的影响,Go 1.21 还引入了工具链管理功能,使得你可以为不同的项目指定不同的工具链版本。这一功能类似于 Node 的 nvm 或 Rust 的 rustup,但它是内置于 Go 的核心工具中。

// go.mod 文件
module examplego 1.21.0
toolchain go1.21.4

在上面的配置中,toolchain go1.21.4 指定了在当前模块中需要使用 Go 1.21.4 工具链。Go 命令会自动下载并使用指定的工具链版本,而无需手动干预。

更新 go.mod 中的 go 行:

go get go@1.21.0,该命令将下载并切换到 Go 1.21.0 版本,并自动更新 go 行。

如果你希望在保持旧版本 go 行不变的情况下更新工具链,可以使用:go get toolchain@go1.21.0。工具链就是run/build/link等等工具。

强制使用特定工具链版本

你可以通过 GOTOOLCHAIN 环境变量来强制使用特定版本的 Go 工具链。

关于环境变量,分为临时的(会话级别的)和永久生效的,优先级临时>永久.

# 查看
go env GOTOOLCHAIN# 设置永久生效(不推荐)
go env -w GOTOOLCHAIN=go1.20# windows系统,设置临时
set GOTOOLCHAIN=go1.20# Linux系统,直接放在命令开头即可
# windows系统不支持这种写法
GOTOOLCHAIN=go1.20 go run main.go

可以理解为在 Go 1.21 以前,我们用的是GOTOOLCHAIN=local,即使用你本地安装的Go版本。

在 Go 1.21 之后,如果Go发现本地工具链版本低于go mod要求的最低版本,那么Go会自动下载匹配的Go工具链,缓存到go module cache(不会覆盖本地安装的go工具链),保存在 pkg/mod 目录下,就像你下载普通的依赖一样,并用新下载的Go工具链对module进行编译构建。

也就是说,你本地现在可以有多个版本的Go工具链,主版本就是你的安装版本,其他的版本就是用来编译。

有时候你可能有多个项目,它们依赖不同的Go版本。

go xxx 就是初始化项目的时候你本地安装的Go版本。

toolchain goxxx 是编译时要求使用的Go版本,出现这种情况,可能是依赖的第三方包要求的Go版本高于你本地安装的版本。

这就是所谓的向前兼容性,开发者可以放心使用新语言特性,无需担心旧版本编译器带来的问题,go命令会自动处理这一切

自动升级工具链

你还可以设置自动升级工具链版本。使用 GOTOOLCHAIN 环境变量的形式 version+auto 可以在保留当前版本的同时允许自动升级。例如:go env -w GOTOOLCHAIN=go1.21.1+auto

当 Go 1.21.1 发布时,你的系统将自动使用该版本。

Go 1.21 的工具链管理功能和向前兼容性改进将大大提升 Go 开发的便利性。通过这些新特性,你可以更好地管理不同版本的工具链,确保代码在不同版本的 Go 中稳定运行。

那么你如何知道Go到底会使用哪个版本编译呢?

方法1:go version

在 go env 的输出中,如果 GOTOOLCHAIN=auto,那么 GOVERSION 的值一般就是安装的Go版本。

终端1:

go env GOTOOLCHAIN
autogo env GOVERSION
go1.23.4go version
go version go1.23.4 windows/amd64

如果设置 GOTOOLCHAIN=go1.20,那么 GOTOOLCHAIN 和 GOVERSION 的值就是一样的。

终端2:

# 设置临时环境变量,只在当前命令行生效
set GOTOOLCHAIN=go1.20go env GOTOOLCHAIN
go1.20go env GOVERSION
go1.20go version
go version go1.20 windows/amd64

go version的值就是 go env GOVERSION的值,也就是说 go version 的确可以预示着会使用哪个版本的Go编译此项目。但是 go version 只是检查到了环境变量这一层,并不会检查go.mod中的toolchain行。

方法2:-x 参数

go run -x main.go
go build -x main.go

会打印出执行过程,能看到使用的是哪个工具链。

终端1:

go run -x main.gomkdir -p $WORK\b001\exe\
cd .
GOROOT='D:\Go' "D:\\Go\\pkg\\tool\\windows_amd64\\link.exe" -o "$WORK\\b001\\exe\\main.exe".......

终端2:

set GOTOOLCHAIN=go1.20go run -x main.gomkdir -p $WORK\b001\exe\
cd .
"D:\\dev\\php\\magook\\trunk\\server\\golang\\path\\pkg\\mod\\golang.org\\toolchain@v0.0.1-go1.20.windows-amd64\\pkg\\tool\\windows_amd64\\link.exe" -o "$WORK\\b001\\exe\\main.exe".......

从结果来看的确是使用了不同版本的工具。

多个版本的Go被保存在PATH/pkg/mod/golang.org/toolchain@v0.0.1-goxxxxx。

Go命令选择版本的规则是什么?

toolchain 行一定要大于等于 go1.21.0,否则会报错,然后 toolchain 行可以大于 go 行,也可以小于 go 行,不会报错。

Go命令会先比较 toolchain 行和 go 行,取大的,然后与本地安装版本比较,取大的,如果结果大于本地版本,才会下载使用新的版本,否则只会使用本地版本,Go保证高版本可以正常编译低版本。

如果你引入的第三方包要求的版本大于go.mod中的go行,且大于本地安装版本,会自动为你加上 toolchain goxxx

在 go1.21.0 之后,go 行,toolchain 行,GOTOOLCHAIN都要精确到三级版本号,否则会报错。

升级到Go1.23.4

把Go升级到大于等于1.21.0已经是不得不做的事情,因为未来很多第三方包会依赖于1.21.0及其以上,而你的项目将无法使用它们,但是这又不是绝对的,在1.20的时候我的项目依赖了1.21.4的包,windows平台可以正常编译,但是darwin则无法编译。

windows系统直接下载msi安装包安装即可。

Linux下载tar.gz直接覆盖即可。

如果不想覆盖只想体验下新版本:go install golang.org/dl/go1.23.0@latest 只会下载Go的可执行文件到 $GOPATH/bin/go1.23.4.exe,并不算版本更新。

Windows系统设置环境变量

在这里插入图片描述

GOSUMDB需要设置,因为如果触发了下载其他版本,就进行校验,如果目标地址设置错误就会报错

go: downloading go1.20 (linux/amd64)
go: download go1.20: golang.org/toolchain@v0.0.1-go1.20.linux-amd64: verifying module: invalid GOSUMDB: malformed verifier id

因为我的项目大多在1.20版本,所以我需要测试一下有没有问题。

一个简单的测试项目go-new

utilutil.go
go.mod
main.go
// go.modmodule go-newgo 1.20
// main.gopackage mainimport ("fmt""go-new/util"
)func main() {fmt.Println(util.Max(1, 2))
}
set GOTOOLCHAIN=go1.20go run main.gomain.go:5:2: ambiguous import: found package go-new/util in multiple modules:go-new (D:\dev\php\magook\trunk\server\go-new\util)(D:\dev\php\magook\trunk\server\golang\path\pkg\mod\golang.org\toolchain@v0.0.1-go1.20.windows-amd64\src\go-new\util)
set GOTOOLCHAIN=go1.19go run main.gomain.go:5:2: cannot find package "go-new/util" in:D:\dev\php\magook\trunk\server\golang\path\pkg\mod\golang.org\toolchain@v0.0.1-go1.19.windows-amd64\src\go-new\util
set GOTOOLCHAIN=go1.18go run main.go可以正常运行

修改 go.mod

module go-newgo 1.21.0
set GOTOOLCHAIN=go1.21.0go run main.go可以正常运行
set GOTOOLCHAIN=go1.22.0go run main.go可以正常运行

由此可见,GOTOOLCHAIN 在低于 1.21.0的时候存在兼容性问题,这意味着,当我升级到Go1.23.4的时候,我过往的项目(依赖于Go1.20及其以下)应该在Go1.21.0版本运行,但是,如果你信任Go官方的话,这些都不需要。

如果我一直停留在Go1.23.4,随着时间的推移,有些第三方包会依赖更高版本的Go,到时候可以用go.mod中的toolchain行来解决,这个会自动被添加上的,不需要操心。

阅读Go的release note可以发现Go基本是保证向前兼容,其新特性是以增量的方式加入的,而不会改变以前版本的特性,但并不代表你可以不关心了,比如上面提到的在Go1.23.0中的time.Timer的特性改动,如果你升级到了1.23但是并不了解其变化而依旧使用之前的方式来编码,结果可能会超出你的认知,导致严重的后果。

在 Go 1.21 之后我们要分清楚几个概念

  • go命令,它与Go版本无关(或淡化),就是个命令。
  • go.mod 中的 go 行,是当前模块开发时的版本要求。
  • go.mod 中的 toolchain 行,是依赖的第三方包的版本要求。
  • 不同版本的Go会像普通的依赖包一样同时存在。
总结

说了那么多,升级到新版本后,我该注意些什么呢?答案是什么也不用。

基于Go的新版本都是增量发布的,不会改变旧的逻辑,即便是不得不大改的time.Timer,Go也会根据go.mod中go行来区别对待,所以我们不要改动go行。放心的使用Go1.23.4来编译Go1.20的项目。

参考

Forward Compatibility and Toolchain Management in Go 1.21

Go Toolchains

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

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

相关文章

Unity中的委托和事件(UnityAction、UnityEvent)

委托和事件 &#x1f392;什么是委托&#xff0c;委托的关键字是Delegate&#xff0c;委托是一种函数的容器&#xff0c;运行将函数做为变量来进行传递 通过Delegate关键字我们声明了一个无参无返回的委托&#xff0c;通过这个委托我们可以存储无参无返回的函数 public deleg…

uniapp v-tabs修改了几项功能,根据自己需求自己改

根据自己的需求都可以改 这里写自定义目录标题 1.数组中的名字过长&#xff0c;导致滑动异常2.change 事件拿不到当前点击的数据&#xff0c;通过index在原数组中查找得到所需要的id 各种字段麻烦3.添加指定下标下新加红点显示样式 1.数组中的名字过长&#xff0c;导致滑动异常…

CAD xy坐标标注(跟随鼠标位置实时移动)——C#插件实现

效果如下&#xff1a; &#xff08;使用方法&#xff1a;命令行输入 “netload” 加载此dll插件&#xff0c;然后输入“zbbz”运行&#xff0c;选择文件夹即可。支持字体大小变化&#xff0c;输入“zbbd”可设置坐标字体变大或缩小的倍数&#xff09; 部分代码如下&#xff1a;…

【C#】实现Json转Lua (Json2Lua)

关键词: C#、JsonToLua、Json2Lua、对象序列化Lua 前提需引入NewtonsofJson&#xff0c;引入方法可先在Visual Studio 2019 将Newtonsoft.Json.dll文件导入Unity的Plugins下。 Json格式字符串转Lua格式字符串&#xff0c;效果如下&#xff1a; json字符串 {"1": &q…

Redis 7.x如何安装与配置?保姆级教程

大家好&#xff0c;我是袁庭新。最新写了一套最新版的Redis 7.x企业级开发教程&#xff0c;今天先给大家介绍下Redis 7.x如何在Linux系统上安装和配置。 1 Redis下载与安装 使用非关系型数据库Redis必须先进行安装配置并开启Redis服务&#xff0c;然后使用对应客户端连接使用…

Redis篇--常见问题篇6--缓存一致性1(Mysql和Redis缓存一致,更新数据库删除缓存策略)

1、概述 在使用Redis作为MySQL的缓存层时&#xff0c;缓存一致性问题是指Redis中的缓存数据与MySQL数据库中的实际数据不一致的情况。这可能会导致读取到过期或错误的数据&#xff0c;从而影响系统的正确性和用户体验。 为了减轻数据库的压力&#xff0c;通常读操作都是先读缓…

git remote -v(--verbose)显示你的 Git 仓库配置的远程仓库的详细信息

git remote -v 是一个 Git 命令&#xff0c;用于显示你的 Git 仓库配置的远程仓库的详细信息。 当你执行 git remote -v 命令时&#xff0c;你会看到类似以下的输出&#xff1a; origin https://github.com/your-username/your-repo.git (fetch) origin https://github.com…

[计算机网络]唐僧的”通关文牒“NAT地址转换

1.NAT&#xff1a;唐僧的通关文牒 在古老的西游记中&#xff0c;唐僧师徒四人历经九九八十一难&#xff0c;终于取得了真经。然而&#xff0c;他们并不是一开始就获得了通关文牒&#xff0c;而是经过了重重考验&#xff0c;最终得到了国王的认可&#xff0c;才顺利通过了各个关…

WPF实现曲线数据展示【案例:震动数据分析】

wpf实现曲线数据展示&#xff0c;函数曲线展示&#xff0c;实例&#xff1a;震动数据分析为例。 如上图所示&#xff0c;如果你想实现上图中的效果&#xff0c;请详细参考我的内容&#xff0c;创作不易&#xff0c;给个赞吧。 一共有两种方式来实现&#xff0c;一种是使用第三…

7 家使用量子计算的公司

劳斯莱斯、Deloitte、BASF、Roche、富士通、JPMorgan和宝马是率先开展量子计算实验的部分公司。 商用量子计算的实现仍需数年时间&#xff0c;但这并未阻止世界上一些知名企业对其进行试验。在许多情况下&#xff0c;利用当下有噪声的中等规模量子&#xff08;NISQ&#xff09…

jvm字节码中方法的结构

“-Xss”这一名称并没有一个特定的“为什么”来解释其命名&#xff0c;它更多是JVM&#xff08;Java虚拟机&#xff09;配置参数中的一个约定俗成的标识。在JVM中&#xff0c;有多个配置参数用于调整和优化Java应用程序的性能&#xff0c;这些参数通常以一个短横线“-”开头&am…

【服务器】MyBatis是如何在java中使用并进行分页的?

MyBatis 是一个支持普通 SQL 查询、存储过程和高级映射的持久层框架。它消除了几乎所有的 JDBC 代码和参数的手动设置以及结果集的检索。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java 的 POJO&#xff08;Plain Old Java Objects&#xff0c;普通老式 …

Phono3py hdf5文件数据读取与处理

Phono3py是一个主要用python写的声子-声子相互作用相关性质的模拟包&#xff0c;可以基于有限位移算法实现三阶力常数和晶格热导率的计算过程&#xff0c;同时输出包括声速&#xff0c;格林奈森常数&#xff0c;声子寿命和累积晶格热导率等参量。 相关介绍和安装请参考往期推荐…

centos7下docker 容器实现redis主从同步

1.下载redis 镜像 docker pull bitnami/redis2. 文件夹授权 此文件夹是 你自己映射到宿主机上的挂载目录 chmod 777 /app/rd13.创建docker网络 docker network create mynet4.运行docker 镜像 安装redis的master -e 是设置环境变量值 docker run -d -p 6379:6379 \ -v /a…

matlab绘图时设置左、右坐标轴为不同颜色

目录 一、需求描述 二、实现方法 一、需求描述 当图中存在两条曲线&#xff0c;需要对两条曲线进行分别描述时&#xff0c;应设置左、右坐标轴为不同颜色&#xff0c;并设置刻度线&#xff0c;且坐标轴颜色需要和曲线颜色相同。 二、实现方法 1.1、可以实现&#xff1a; 1…

【数据可视化复习方向】

1.数据可视化就是数据中信息的可视化 2.数据可视化主要从数据中寻找三个方面的信息&#xff1a;模式、关系和异常 3.大数据可视化分类&#xff1a;科学可视化、信息可视化、可视分析学 4.大数据可视化作用&#xff1a;记录信息、分析推理、信息传播与协同 5.可视化流程&…

「配置应用的可见性」功能使用教程

引言 对于「应用可见性」这一概念&#xff0c;可能很多开发者小伙伴还不是很熟悉。简单举一个很典型的场景例子&#xff0c;当你开发的应用需要调起第三方应用时&#xff0c;这里就涉及到应用可见性的问题了&#xff0c;如果不配置相关的应用可见性&#xff0c;则你的应用是无…

Pytorch | 从零构建ResNet对CIFAR10进行分类

Pytorch | 从零构建ResNet对CIFAR10进行分类 CIFAR10数据集ResNet核心思想网络结构创新点优点应用 ResNet结构代码详解结构代码代码详解BasicBlock 类ResNet 类ResNet18、ResNet34、ResNet50、ResNet101、ResNet152函数 训练过程和测试结果代码汇总resnet.pytrain.pytest.py 前…

安装MongoDB,环境配置

官网下载地址&#xff1a;MongoDB Shell Download | MongoDB 选择版本 安装 下载完成双击打开 点击mongodb-windows-x86_64-8.0.0-signed 选择安装地址 检查安装地址 安装成功 二.配置MongoDB数据库环境 1.找到安装好MongoDB的bin路径 复制bin路径 打开此电脑 -> 打开高级…

7.C语言 宏(Macro) 宏定义,宏函数

目录 宏定义 宏函数 1.注释事项 2.注意事项 宏(Macro)用法 常量定义 简单函数实现 类型检查 条件编译 宏函数计算参数个数 宏定义进行类型转换 宏定义进行位操作 宏定义进行断言 总结 宏定义 #include "stdio.h" #include "string.h" #incl…