简介
最近Golang新版本1.13发布,距离上一个版本1.12,只有六个月。该版本主要带来了工具链,运行时和库的变化。根据承诺规则,该版本保持与现有1.x版本的兼容。从Golang 1.13开始,Go命令默认启用Go模块镜像和统一的包数据校验逐步解决了Golang三大问题(包版本管理”、”错误处理机制”和”泛型”)中的包版本管理的问题,更多功能变化请追随虫虫一起学习。
语法变化
根据数字字面量提案(number literal proposal),Go 1.13支持更加统一和现代化的数字语法前缀。
二进制 整数:通过前缀0b或0B表示二进制整数文字,例如0b1011。
八进制 整数:通过前缀0o或0O(前面是数字零,后面的是字母o)表示八进制整数文字,例如0o660。由前缀0后跟八进制数字的现有八进制表示法仍然有效。
十六进制 浮点数 :通过前缀0x或0X表示十六进制格式的浮点数的尾数,例如0x1.0p-1021。十六进制浮点数必须包含指数,用字母p或P表示,后跟十进制的指数。表示以2为底数的指数级幂。
复数 : 虚数 后缀i可以与任何(二进制,十进制,十六进制)整数或浮点数一起使用。
数字分隔符:可以对任何数字,使用下划线分隔(分组),例如在1_000_000,0b_1010_0110或3.1415_9265中。下划线可能出新版本任何两位数字或数字前缀和第一位数字之间。
根据有符号整数移位计数提案(signed shift counts proposal),Golang 1.13取消了变化计数必须是无符号数的限制。该变化可以消除许多需要人工uint转换的工作,这些转换仅用于满足<<和>>运算符的限制。
这些语法变化是通过对编译器的更改以及对内部核心包go/scanner,text/scanner(数字字面量)以go/types(有符号整数移位计数)的变化来实现的。
升级golang到最新版本后,还需在代码中和go.mod指定了最新的版本才能访问这些变化。可以直接通过编辑go.mod文件或者运行go mod edit -go = 1.13来实现。
发行Port
Go 1.13将是支持Native Client(NaCl)最后一个版本。对于GOARCH = wasm,新的 环境变量 GOWASM采用以逗号分隔的二进制编译的实验性功能。
AIX
PPC64上的AIX(aix/ pc64)新版本支持cgo,外部链接以及c-archive和pie构建模式。
Android
Golang程序新版本与Android 10兼容。
Darwin
Go 1.12发行版中已经介绍过,Go 1.13需要macOS 10.11 El Capitan或更新的版本,已经停止对更老版本的支持。
FreeBSD
同样Go 1.13新版本需要FreeBSD 11.2或更新版本,已经停止对更老版本的支持。 FreeBSD 12.0或更新版本需要一个设置了COMPAT_FREEBSD11选项的内核(默认设置)。
Illumos
Go新版本用GOOS = illumos来支持Illumos。 illumos构建标记也表示solaris构建标记。
Windows
新版本内部链接的Windows二进制文件指定的Windows版本是Windows 7,最低支持版本为Window 7,这可能会影响具有向后兼容模式的系统调用的行为。外部链接二进制文件(使用cgo的程序)需要指定新一点的Windows版本。
工具链
环境变量
GO111MODULE默认为auto,当前工作目录包含go.mod文件或者为go.mod目录的子目录,就会自动设置激活go命令的模块感知模式,这和当前目录在GOPATH/src情况等效。这简化了GOPATH/src中已有代码的迁移,以及模块感知软件包与非模块感知模块引用的维护。
新的GOPRIVATE环境变量可以配置不能公开发布的私有模块路径。它可以用于较低级别GONOPROXY和GONOSUMDB变量的默认值,它们通过代理提取模块并使用校验数据库进行验证,从而提供更精细的控制。
GOPROXY环境变量支持配置为以逗号分隔的代理URL列表或特殊令牌direct,其默认值新版本为proxy.golang.org,direct。解析包含其模块的包路径时,go命令将连续尝试列表中每个代理上的所有候选模块路径。如果代理无法访问或者返回404或410 等状态代码将终止搜索。该配置对于国内的Golang开发者是个福音了,可以使用国内的goproxy.io的代理,而无需考虑由于网络无法下载模块的问题了。
go env -w GOPROXY=
新版本GOSUMDB环境变量使用名称,服务器URL以及可选的公钥来校验模块,通过查询主模块的go.sum文件中尚未列出的模块的校验和。如果GOSUMDB不包含显式URL,则通过探测指示支持校验数据库的端点的GOPROXY URL来选择URL,如果任何代理都不支持,则返回到指定数据库的直接连接。如果GOSUMDB设置为off,则不会查询校验数据库,只验证go.sum文件中的现有校验和。
由于防火墙或沙盒配置,无法访问默认代理和校验数据库的用可以通过将GOPROXY设置为直接和/或将GOSUMDB设置为off来禁用。也可以通过go env –w命令来设置这些变量的默认值:
go env -w GOPROXY=direct go env -w GOSUMDB=off
go get
在模块感知模式下,使用go get -u标志新版本更新为模块的较小集更新,和GOPATH模式下go get -u软件包更新更一致。go get -u继续更新命令行上命名的模块和包,但只叠加更新包含命名包引入的包,而不会更新包命名包的模块间接引入的包。
需要特别注意的,get get -u(没有附加参数)只更新当前目录中包的间接引入的包。要想更新主模块引用的所有包(包括测试依赖项),需要使用go get -u all。
由于上面的变化go get -u,go get子命令不再支持-m标志。-d标志还支持,并且会下载构建命名包的依赖关系所需的源代码。
默认情况下,在模块模式下获取-u仅升级非测试依赖项,和GOPATH模式一致。新支持-t标志,(在GOPATH模式下)用于go get引入由命令行命名的包的测试引入的包。
在模块感知模式下,go get子命令新版本支持版本后缀 @patch 。 @patch 后缀表示指定的模块或包含命名包的模块只更新小版本,大版本和次要版本保持不变。比如从v1.2.4升级到v1.2.5
如果在没有版本后缀的默认会情况下会请求latest版本。这与模块依赖性的-u标志的行为一致。这可以防止意外降级请求预发布版本。新版本后缀 @upgrade 显式请求预发布版本。 @latest 显式请求latest版本。
版本校验
从版本控制系统中提取模块时,go命令新版本对请求的版本 字符串 执行附加校验。
+incompatible版本注释绕过引入模块之前的存储库的语义化版本引入控制的要求。go命令新版本验证这样的版本不包含显式的go.mod文件。
go命令行会验证伪版本和版本控制元数据之间的映射:
版本前缀必须为vX.0.0形式,或者从指定命名版本的祖先上的标记派生,或者从包含命名版本本身的构建元数据的标记派生。
日期字符串必须与版本的UTC时间戳匹配。
版本的短名称必须使用与go命令生成的字符数相同的字符数。(如果为git版本,则为SHA-1哈希,前12位。)
如果主模块中的require指令使用的是无效的伪版本,通常可以通过将版本重新编写为提交哈希,然后重新运行go命令来更正。例如go list -m all或go mod tidy。例如,
require github.com/ docker /docker v1.14.0-0.20190319215453-e7b5f7dbe98c
可以编辑为
require github.com/docker/docker e7b5f7dbe98c
如果主模块的其中一个依赖项为无效版本或伪版本,则可以在主模块的go.mod文件中用replace指令将无效版本替换为有效版本。如果替换时提交的为哈希值,它将被解析为适当的伪版本,如上所述。例如
replace github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c => github.com/docker/docker e7b5f7dbe98c
会被解析为
replace github.com/docker/docker v1.14.0-0.20190319215453-e7b5f7dbe98c => github.com/docker/docker v0.7.3-0.20190319215453-e7b5f7dbe98c
go命令行
go env命令,通过-w标志来设置用户默认的环境变量,用-u标志来取消之前设置的默认值。go env -w设置的默认值存储在os.UserConfigDir()目录下的go/env文件中。
go version命令接受 可执行文件 以及目录作为参数。在可执行文件上调用该命令时,go version会打印构建该可执行文件的Go版本。如果使用-m标志,go version会打印可执行文件的嵌入的模块版本信息)。在目录上调用时,go version会打印有关目录及其子目录中包含的可执行文件的信息。
go build新增加-trimpath标志,用来从已编译的可执行文件中删除所有文件系统路径,以提高构建可重现性。如果传递给go build的-o标志引用了现有目录,那么go build会在该目录中生成与其包参数匹配的主包可执行文件。
go build标志-tags更新为使用逗号分隔的构建标记列表,来支持GOFLAGS中的多个标记。空格分隔的语法已经被弃用但仍可识别和维护。
go generate会设置generate构建标签,可以用来搜索文件中的指令,但在构建期间忽略这些指令。
和Go 1.12发布中已经提到的,1.13版本不再支持仅为二进制包。构建仅二进制包(标记为//go:binary-only-package注释)会抛出错误。
编译器
编译器新增加一个更精确的逃逸分析实现。对于大多数Go代码应该是一个改进(换句话说,更多的Go变量和表达式分配在堆栈而不是堆)。但是,这种提高的精度实现,也可能会导致此前一些可以运行的无效代码(例如,违反unsafe.Pointer安全规则的代码)。如果有类似的代码,暂时可用
go build -gcflags = all = -newescape = false重新启用旧的转义分析过程。将来的版本中将会彻底删除使用旧转义分析的选项。
编译器不再向go_asm.h文件传递浮点或复数常量。它们始终以不能在汇编代码中以数字常量的形式传递。
汇编
汇编程序新版本支持ARM v8.1中引入的许多原子指令。
gofmt
gofmt(go fmt)新版本规范化数字前缀和指数以使用小写字母,但仅保留十六进制数字。当使用新的八进制前缀(0O变为0o)并且一致地应用重写时,这提高了可读性。gofmt新版本还从十进制整数虚数中删除不必要的前导零。(为了向后兼容,从0开始的整数虚数被认为是十进制,而不是八进制数。删除多余的前导零可以避免潜在的混淆。)
例如,0B1010,0XabcDEF,0O660,1.2E3和01i变为:
0b1010,0xabcDEF,0o660,1.2e3和1i
godoc和go doc
godoc webserver从二进制主发行包中删除。需要在本地运行godoc webserver,请先手动安装它:
go get golang.org/x/tools/cmd/godoc godoc
除了命令之外,go doc命令新版本总是在其输出中包含package子句。这取代了先前使用启发式的行为,导致在某些条件下省略package子句。
运行时
超出范围的panic错误消息新版本包括超出范围的索引和切片的长度(或容量)。比如:
s[3] on a slice of length 1 will panic with "runtime error: index out of range [3] with length 1".
新版本将大多数使用defer的性能提高了30%。
新本中运行时更积极地将内存返回给操作系统,以使其可供共同租户应用程序使用。之前,运行时可能会在堆大小增加后保留内存五分钟或更长时间。新版本将在堆缩小后立即开始返回它。但是,在许多操作系统(包括Linux)上,操作系统本身都会惰性回收内存,因此在系统处于内存压力之前,进程RSS不会减少。
核心库更新
TLS 1.3
Go 1.13默认通过crypto/tls包中启用TLS 1.3。可以通过将值tls13 = 0添加到GODEBUG环境变量来禁用该默认行为。该临时禁止选项将在Go 1.14会删除。
crypto/ed25519
新的crypto/ed25519包实现了Ed25519签名方案。此功能此前由golang.org/x/crypto/ed25519包提供,在1.13版本以后打包为crypto/ed25519包装器。
错误打包
Go 1.13包含了错误值议案(Error Values proposal)以及相关问题上讨论的一些错误功能的打包。
错误e可以通过提供返回w的Unwrap方法来打包另一个错误w。e和w都可用于程序,允许e为w提供额外的上下文或重新解释它,同时仍然允许程序基于w做出决策。
为了支持打包fmt.Errorf新版本有一个%w动词用于创建打包errors,错误包中的三个新函数(errors.Unwrap,errors.Is和errors.As)简化了展开和检查打包错误。
其他库变化
和每次发行包一样,11.3版本也带了各个库的各种微小的变化和更新,并遵守对Go 1的兼容性
bytes
新的ToValidUTF8函数返回给定字节切片的副本,每次运行的无效UTF-8字节序列由给定切片替换。
context
WithValue返回的上下文格式不再依赖于fmt,也不会以相同的方式进行字符串化。依赖于之前字符串化的代码可能会受到影响。
crypto/tls
现已弃用对SSL 3.0版(SSLv3)的支持,会在Go 1.14中删除。
默认情况下,在默认服务器端错误地启用SSLv3时,默认情况下始终禁用SSLv3。 (客户端从不支持SSLv3。)
TLS版本1.2和1.3新版本支持Ed25519证书。
crypto/x509
根据RFC 8410,认证和认证请求中支持Ed25519密钥。ParsePKCS8PrivateKey,MarshalPKCS8PrivateKey和ParsePKIXPublicKey函数也同步支持。
搜索系统根目录的路径新版本包括/etc/ssl/cert.pem,以支持Alpine Linux 3.7+中的默认路径。
database/sql
新的NullTime类型表示time.Time可能为null。
新的NullInt32类型表示可能为null的int32。
debug/dwarf
如果在类型图中遇到未知的DWARF标记,则Data.Type方法不再发生混乱。相反,它表示为具有UnsupportedType对象的类型的组件。
erros
新函数As查找给定错误链(包装错误序列)中与给定目标类型匹配的第一个错误,如果是,则将目标设置为该错误值。
新函数Is报告给定的错误值是否与另一个链中的错误匹配。
新函数Unwrap返回在给定错误(如果存在)上调用Unwrap的结果。
FMT
print中谓词动词%x和%X,表示以小写和大写形式格式化浮点和复数。
新的print中谓词%O表示八进制整数
scanner新版本接受十六进制浮点值,数字分隔下划线和0b和0o前缀。
Errorf函数,新添加一个谓词%w,其操作数必须是一个错误。从Errorf返回的error对象支持Unwrap方法,它返回%w的操作数。
go/scanner
scanner程序已更新,以识别新的Go数字格式,特别是具有0b/0B前缀的二进制数字,0o/0O为前缀的八进制数字及十六进制尾数的浮点数。复数虚部后缀i支持与任意数字一起使用,下划线可以用作数字分隔符进行分组。
go/types
类型检查器已更新为遵循整型变化的新规则。有关详细信息,请参阅语言更改。
html/template
当使用<script>标记并将”module”设置为type属性时,代码新版本将被解释为JavaScript模块脚本。
log
新的Writer函数返回标准记录器的输出目标。
math/big
新的Rat.SetUint64方法将Rat设置为uint64值。
对于Float.Parse,如果base为0,则可以在数字之间使用下划线以提高可读性。
对于Int.SetString,如果base为0,则可以在数字之间使用下划线以提高可读性。
Rat.SetString新版本接受非十进制浮点表示。
math/bits
现Add,Sub,Mul,RotateLeft和ReverseBytes的执行时间保证独立于输入。
net
在Unix系统上use-vc设置位于resolv.conf,DNS解析使用TCP协议。
新字段ListenConfig.KeepAlive指定侦听器接受的网络连接的保持活动时间。如果此字段为0(默认值),则将启用TCP保持活动。要禁用,需要将其设置为负。
net/http
新字段Transport.WriteBufferSize和Transport.ReadBufferSize允许指定传输的写入和读取缓冲区的大小。如果任一字段为零,则使用默认大小4KB。
新字段Transport.ForceAttemptHTTP2控制在提供非零Dial,DialTLS或DialContext函数或TLSClientConfig时是否启用HTTP/2。
Transport.MaxConnsPerHost在新版本中可以正常使用HTTP/2。
TimeoutHandler的ResponseWriter在新版本中实现了Pusher和Flusher接口。
添加StatusCode 103″早期提示”。
Transport在新版本使用Request.Body的io.ReaderFrom实现(如果可用)来优化写入正文。
在遇到不支持的传输编码时,http.Server在新版本中返回HTTP规范RFC 7230第3.3.1节规定的”501未实现”状态。
新的服务器字段BaseContext和ConnContext允许更好地控制提供给请求和连接的Context值。
http.DetectContentType在新版本可以正确检测RAR签名,还可以检测RAR v5签名。
新的Header方法Clone返回接收器的副本。
添加了一个新函数NewRequestWithContext,接受一个Context控制创建的传出请求的整个生命周期,适用于Client.Do和Transport.RoundTrip。
当服务器使用”408请求超时”响应正常关闭空闲连接时,传输不再记录错误。
os
新的UserConfigDir函数返回用于特定于用户的配置数据的默认目录。
如果使用O_APPEND标志打开文件,则其WriteAt方法将始终返回错误。
os/exec
在Windows上,除非Cmd.Env字段包含显式值,否则Cmd的环境始终会继承父进程的%SYSTEMROOT%值。
reflect
新的Value.IsZero方法报告Value是否为其类型的零值。
MakeFunc函数新版本允许对返回值进行赋值转换,而不是要求精确类型匹配。当返回的类型是接口类型时,这尤其有用,但实际返回的值是实现该类型的具体值。
runtime
Tracebacks,runtime.Caller和runtime.Callers新版本中引用将PKG的全局变量初始化为PKG.init,而不是PKG.init.ializers的函数。
strconv
对于strconv.ParseFloat,strconv.ParseInt和strconv.ParseUint,如果base为0,则可以在数字之间使用下划线以提高可读性。
strings
新的ToValidUTF8函数返回给定字符串的副本,每次运行的无效UTF-8字节序列由给定字符串替换。
sync
Mutex.Lock,Mutex.Unlock,RWMutex.Lock,RWMutex.RUnlock和Once.Do的快速路径在新版本中调用器中内联。对于amd64上的无竞争情况,这些更改使Once.Do的速度提高了一倍,而Mutex/RWMutex方法的速度提高了10%。
大型程序池不再增加stop-the-world暂停时间。
每次GC后,程序池不再需要完全重新填充。它新版本保留了跨GC的一些对象,而不是释放所有对象,减少了大量用户的负载峰值。
syscall
_getdirentries64的使用已从Darwin构建中删除,以允许将Go二进制文件上载到macOS App Store。
SysProcAttr中的新ProcessAttributes和ThreadAttributes字段已针对Windows引入,在创建新进程时公开安全设置。
在Windows上,不再以零Chmod模式返回EINVAL。
syscall/js
TypedArrayOf已被CopyBytesToGo和CopyBytesToJS取代,用于在字节切片和Uint8Array之间复制字节。
testing
运行基准测试时,B.N不再是四舍五入。
新方法B.ReportMetric允许用户报告自定义基准指标并覆盖内置指标。
测试标志新版本在新的Init函数中注册,该函数由生成的测试主函数调用。因此,新版本只在运行测试二进制文件时注册测试标志,并且在程序包初始化期间调用flag.Parse的程序包可能导致测试失败。
text/scanner
scanner程序已更新,以识别新的Go数字格式。
text/template
新切片函数返回通过以下参数切片其第一个参数的结果。
time
Format和Parse新版本支持日期。
新的Duration方法Microseconds和Milliseconds将持续时间作为其各自命名单元的整数计数返回。
unicode
整个系统中的unicode包和相关支持已从Unicode 10.0升级到Unicode 11.0,后者增加了684个新字符,包括7个新脚本和66个新表情符号。