Go 1.18 发布说明
介绍 Go 1.18
Go最新release,版本1.18,是一个重大的release,包含了语言上的改变,工具链、runtime和库的实现。Go 1.18在Go 1.17发布7个月之后到来。和往常一样,考虑到了Go 1的兼容性承诺。我们希望所有的Go程序可以向之前一样继续编译和运行。
Go语言的变化
泛型
Go 1.18包含一个在类型参数提案中描述的泛型特性的实现,这包括对语言的重大–但完全向后兼容的–改变。
这些新的变化需要编写大量新的代码,然而这些代码还没有在生产环境中进行过大量的测试。这只会在当越来越多人编写和使用泛型的时候才会发生。我们相信这些新特性的实现是优雅的,并且是高质量的。然而,与Go大多数方面不同的是,我们无法用现实世界的经验来支持这种信念。因此,虽然我们鼓励在某些需要使用的泛型的场景下使用泛型,但当部署泛型代码到生产环境时,请多谨慎一些。
虽然我们相信新的语言功能设计得很好,而且规定得很清楚,但我们有可能犯了错误。我们想要强调的是Go 1 兼容保证上说 “如果有必要解决规范中的不一致或不完整,但是解决这个问题可能会影响现有程序的意义或合法性。那我们保留解决此类问题的权利,包括更新实施。”它也陈述了“如果一个编译器或库有一个违反规范的bug,那么如果这个bug被修复,依赖于这个bug行为的程序可能会被破坏。我们保留修复此类bug的权利。”换句话说,有可能会有一些使用泛型的代码在1.18版本中可以使用,但在以后的版本中会出现问题。我们不计划也不期望做出任何此类改变。然而,在未来的版本中,由于我们今天无法预见的原因,调整1.18的程序可能成为必要。我们将尽可能地减少任何此类调整变动,但我们不能保证变动的几率为零。
以下是最明显的变化列表。关于更全面的概述,请看提案。详情见语言规范。
函数和类型宣告的语法,现在接受类型参数。
参数化的函数和类型可以通过在它们后面加上类型参数列表来进行实例化,类型参数列表放在方括号中。
添加了新的标识 ~ 到运算符和标点符号。
接口类型的语法现在已经支持嵌套任意类型(不只是接口的类型名称),以及union和 ~T 类型元素。这样的接口只能作为类型约束使用。现在一个接口定义了一组类型以及一组方法。
新的提前宣告标识符(prdeclared identifyer) any 作为空接口的别名。这将取代原有的 interface{}
新的提前宣告标识符(prdeclared identifyer) comparable 是一个接口表示所有可以通过==或者!=来比较的类型的集合。它只能用于(或者嵌套)一个类型约束。有三个使用泛型实现的实验性质的包可能会有用。这些包在 x/exp仓库;它们的API不在Go的保证范围内,而且随着我们对泛型经验的增加,可能会发生变化。
goland.org/x/exp/constraints
对泛型代码有用的约束,例如constraints.Ordered
golang.org/x/exp/slices
一个泛型函数的集合,可以对任何元素类型的切片进行操作。
golang.org/x/exp/maps
一个泛型函数的集合,可以对任何键或元素类型的map进行操作。
现在泛型的实现还有如下的限制:
Go编译器目前不能处理泛型函数或者方法内的类型声明。我们希望在Go 1.19提供这个特性。
Go编译器目前在预先声明函数的参数类型上不支持
real
、imag
和complex
类型。我们希望在Go 1.19移除这个限制。如果
m
是由P
的约束接口明确声明的,那Go编译器目前只支持在参数类型为P
的值x
上调用方法m
。同样的,只在m
是由P
的约束接口明确声明的,才支持方法值x.m和方法表达式P.m, 即使由于P中的所有类型都实现了m,导致m在P的方法集中也不能支持上述的使用方式。我们希望在Go 1.19移除这个限制。不允许将类型参数或指向类型参数的指针作为结构类型中的未命名字段嵌入。同样的,不允许将类型参数嵌入到一个接口类型。这个是否会被允许,目前还是未知的。
有一个以上元素的集合元素不能包含一个具有非空方法集的接口类型。这个是否会被允许,目前还是未知的。泛型也代表着Go生态系统会有大量的变动。虽然我们已经更新了一些核心工具来对泛型做支持,但是还有很多许需要去做的。剩下的工具、文档和库需要时间来赶上这些语言发生的变化。
Bug修复
Go 1.18 编译器现在可以正确报告在函数字面中设置,但从未使用的变量的声明错误。在Go 1.18之前,编译器在这种情况下不会报告错误。这修复了长期存在的编译器问题。由于这一变化,(可能是不正确的)程序可能不再被编译。可以直接这么修改:如果程序实际上是不正确的,就修复它,或者使用了违规的变量,例如把它赋值给空白标识符_
。由于go vet
总是指出这个错误,受影响的程序数量可能非常少。
当将一个符文常量表达式,例如'1' << 32
,作为一个参数传递给预先声明函数print
和pintln
时,Go 1.18编译器会报告溢出,与用户定义的函数的行为一致。在Go 1.18之前,编译器对此情况不是报错误,而是如果它符合int64
的要求,就会接收它。由于这一变化,(可能是不正确的)程序可能不再被编译。可以直接这么修改:如果程序实际上是不正确的,就修复它,或者使用了违规的变量,例如把它赋值给空白标识符_
。由于go vet
总是指出这个错误,受影响的程序数量可能非常少。
Ports
AMD64
Go 1.18介绍了新的环境变量GOAMD64
,它在编译时选择了AMD64架构的最小目标版本。允许的值是v1
,v2
,v3
,或者v4
。每一个更高的级别都需要并利用额外的处理器功能。详细的描述可以在这里找到。
GOAMD64
环境变量默认是v1
。
RISC-V
Linux 上的RISC-V 64位架构 (the linux/riscv64
port) 现在支持c-archive
和c-shared
构建模式。
Linux
Go 1.18需要Linux内核版本2.6.32或更高版本。
Windows
windows/arm
and windows/arm64
ports现在支持非合作式抢占,从而使所有四个 Windows ports都具备了这种能力,这有望解决在调用 Win32 函数时遇到的长时间阻塞的微妙错误。
iOS
在iOS(ios/arm64 port)和基于AMD64的macOS(ios/amd64 port)上运行的iOS模拟器上,Go 1.18现在需要iOS 12或更高版本;对以前版本的支持已经停止了。
FreeBSD
Go 1.18是在FreeBSD 11.x上支持的最后一个版本,FreeBSD 11.x已经到了生命末期。Go 1.19 将需要 FreeBSD 12.2+ 或 FreeBSD 13.0+。FreeBSD 13.0+ 需要一个设置了 COMPAT_FREEBSD12 选项的内核(这是默认的)。
工具
Fuzzing
Go 1.18包含了the fuzz