Go 1.19要来了,看看都有哪些变化-第4篇

2022年7月15日 178点热度 0人点赞 0条评论

前言

Go官方团队在2022.06.11发布了Go 1.19 Beta 1版本,Go 1.19的正式release版本预计会在今年8月份发布。

让我们先睹为快,看看Go 1.19给我们带来了哪些变化。

这是Go 1.19版本更新内容详解的第4篇,欢迎大家关注公众号,及时获取本系列最新更新。

第1篇主要涉及Go泛型的改动、Go内存模型和原子操作的优化,原文链接:Go 1.19版本变更内容第1篇

第2篇主要涉及Go文档注释(doc comments)、编译约束(build constraint)以及Go命令的修改,原文链接:Go 1.19版本变更内容第2篇

第3篇主要涉及Go运行时、编译器、汇编器和链接器方面的改动和优化,原文链接:Go 1.19版本变更内容第3篇

Go 1.19发布清单

和Go 1.18相比,改动相对较小,主要涉及语言(Language)、内存模型(Memory Model)、可移植性(Ports)、Go Tool工具链、运行时(Runtime)、编译器(Compiler)、汇编器(Assembler)、链接器(Linker)和核心库(Core library)等方面的优化。

本文重点介绍Go 1.19版本在核心库(Core library)方面的变化。

新的原子类型(New atomic types)

`sync/atomic`[1]包里现在定义了新的类型:`Bool`[2], `Int32`[3], `Int64`[4], `Uint32`[5], `Uint64`[6], `Uintptr`[7], and `Pointer`[8]

这些新的类型定义了相应的原子方法,要修改或者读取这些类型的变量的值就必须使用该类型的原子方法,这样可以避免误操作。

type Bool struct {
 // contains filtered or unexported fields
}

func (x *Bool) CompareAndSwap(old, new bool) (swapped bool)
func (x *Bool) Load() bool
func (x *Bool) Store(val bool)
func (x *Bool) Swap(new bool) (old bool)

比如上面的sync/atomic包里的Bool类型就有4个原子方法,要读取或者修改atomic.Bool类型的变量的值就要使用这4个方法。

sync/atomic包有了Pointer类型后,开发者不需要先把变量转成unsafe.Pointer类型再去调用sync/atomic包里的函数,直接使用Pointer类型的原子方法即可。

Int64Uint64类型在结构体(structs)和分配的内存里会自动按照64位自动对齐,即使在32位系统上也是按照64位对齐。

路径查找(PATH lookups)

`Command`[9]`LookPath`[10] 不再允许在当前目录查找可执行程序,这个修改解决了一个常见的安全问题[11],但是也带来了破坏性更新。

比如以前有段代码是exec.Command("prog"),表示要执行当前目录下名为prog的可执行文件(在Windows系统上对应的是prog.exe),那使用Go 1.19后就不会生效了。可以参考 `os/exec`[12] 包的说明来修改代码以适配CommandLookPath的改动。

在Windows系统上,CommandLookPath现在会感知 `NoDefaultCurrentDirectoryInExePath`[13] 环境变量。我们可以在Windows系统上设置该环境变量来禁止从当前目录. 查找可执行程序。

核心库的微小改动

Go标准库在Go 1.19版本有很多细微的改动和优化,主要涵盖以下内容:

  • archive/zip[14]

    `Reader`[15] 现在会忽略掉ZIP文件开头的非ZIP数据部分,这在读一些Java的JAR文件时会很有必要。

  • crypto/rand[16]

    `Read`[17] 不再缓存从操作系统里获取的随机数。对于Plan 9操作系统,Read被重新实现了,用fast key erasure替换掉了ANSI X9.31算法。

  • crypto/tls[18]

    tls10default GODEBUG 选项在Go 1.19版本已经被移除。不过,我们还是可以通过设置 `Config.MinVersion`[19] 来支持client侧使用TLS 1.0协议。根据RFC 5246中7.4.1.4章节和RFC 8446中4.2章节的要求,TLS server和client现在会拒绝TLS握手里重复的扩展(duplicate extensions)。

  • crypto/x509[20]

    `CreateCertificate`[21] 不再支持使用MD5WITHRSA的签名算法来创建证书。

    CreateCertificate 不再接受SerialNumber为负数。

    `ParseCertificate`[22]`ParseCertificateRequest`[23] 现在会拒绝包含有重复扩展的证书和CSR(Certifcate Signing Request)。

    新方法 `CertPool.Clone`[24]`CertPool.Equal`[25] 可以克隆一个CertPool,并且检查2个CertPool是否相同。

    新函数 `ParseRevocationList`[26] 提供了一个更快、更安全的方式去使用CRL解析器(parser)。

  • crypto/x509/pkix[27]

    `CertificateList`[28]`TBSCertificateList`[29] 现在被废弃了,应该使用新的 `crypto/x509` CRL functionality[30]

  • debug[31]

    新的 EM_LONGARCH and R_LARCH_* 常量现在支持龙芯loong64架构。

  • debug/pe[32]

    引入了新方法 `File.COFFSymbolReadSectionDefAux`[33] ,该方法返回 `COFFSymbolAuxFormat5`[34]类型,可以让开发者访问PE文件里的COMDAT信息。

  • encoding/binary[35]

    新接口 `AppendByteOrder`[36] 提供了高效的方法用于把 uint16uint32,或 uint64 添加到一个byte切片里。

    `BigEndian`[37]`LittleEndian`[38] 都实现了该接口。

  • encoding/csv[39]

    新方法 `Reader.InputOffset`[40] 会返回当前读到的位置,以偏移的字节数来表示,类似于 encoding/json包里的 `Decoder.InputOffset`[41]

  • encoding/xml[42]

    新方法 `Decoder.InputPos`[43] 会返回当前读到的位置,以行和列来表示,类似于 encoding/csv包里的 `Decoder.FieldPos`[44]方法。

  • flag[45]

    新函数 `TextVar`[46] 定义了一个 `encoding.TextUnmarshaler`[47]参数,允许命令行里传入的flag变量使用 `big.Int`[48], `netip.Addr`[49]`time.Time`[50]类型。

  • fmt[51]

    新函数 `Append`[52], `Appendf`[53]`Appendln`[54] 可以添加格式化的数据到byte切片中。

  • go/parser[55]

    go/parser会把 ~x解析为一元表达式(unary expression),其中操作符是~~操作符的官方说明参考 token.TILDE[56]

    当类型约束(type constraint)用在错误的上下文时,比如~int,可以允许更好的错误恢复。

  • go/types[57]

    新方法 `Func.Origin`[58]`Var.Origin`[59] 会返回 `Func`[60]`Var`[61] 实例化后的对象。

  • hash/maphash[62]

    新函数 `Bytes`[63]`String`[64] 提供了高效的方式用于对一个byte slice或者字符串做hash。

  • html/template[65]

    `FuncMap`[66] 类型现在是text/template包里 `FuncMap`[67] 类型的别名,本身不再是一个独立的类型。

  • image/draw[68]

    当目标图像和源头像都是`image.NRGBA`[69] 或者都是 `image.NRGBA64`[70] 类型时,operator为 `Src`[71]`Draw`[72] 会保留non-premultiplied-alpha颜色。

    其实Go 1.17及更早版本的行为就是如此,但是Go 1.18版本做库优化的时候改变了这个行为,Go 1.19版本将这个行为还原了。

  • io[73]

    `NopCloser`[74]的结果现在实现了 `WriterTo`[75] 接口。

    `MultiReader`[76]的结果现在无条件地实现了 `WriterTo`[77]。如果任何底层的reader没有实现WriteTo,也会模拟WriteTo的行为。

  • mime[78]

    .js扩展名的文件本来应该被mime包识别为 text/plain类型,但是在Windows系统上有bug,会导致以.js为扩展名的文件被mime包识别为text/javascript; charset=utf-8类型。

    如果在Windows系统上,想让以.js为扩展名的文件被mime包识别为 text/plain ,必须显示调用 `AddExtensionType`[79]

  • net/http[80]

    `ResponseWriter.WriteHeader`[81] 现在支持发送用户自定义的1xx信息头(informational header)。

    `MaxBytesReader`[82] 的返回值 io.ReadCloser在超过读上限(read limit)后,会返回一个错误类型 `MaxBytesError`[83]

    HTTP client会把状态码为3xx但是没有Location header的Http Response返回给调用者,而不是直接当做错误处理。

  • net/url[84]

    新增的 `JoinPath`[85] 函数 和 `URL.JoinPath`[86] 方法可以把一组path元素组合在一起,创建一个新的 URL

    URL类型现在会区分没有host的URL和host为空的URL。举个例子, http:///path 是有host的,只是host为空,但是 http:/path 就没有host。

    当URL的host为空时,`URL`[87] 类型里的字段 OmitHost 的值会被设置为true

  • os/exec[88]

    如果 `Cmd`[89] 类型的 Dir 字段非空, Env字段为nil,会隐式地为子进程设置PWD环境变量,值为Dir字段的值。

    新方法 `Cmd.Environ`[90] 可以获取到运行cmd的环境,包括隐式设置的PWD环境变量。

  • reflect[91]

    `Value.Bytes`[92] 方法现在除了接收slice切片,现在还接收可取址的数组(addressable array)。`Value.Len`[93]`Value.Cap`[94] 方法现在可以操作指向数组的指针,返回数组的长度。

  • regexp/syntax[95]

    Go 1.18 release candidate 1, Go 1.17.8和 Go 1.16.15 这3个版本包含了对正则表达式解析可能带来的安全问题的修复,会拒绝嵌套很深的正则表达式。由于Go的补丁版本不能引入新的API,对于这种情况,解析器会返回 `syntax.ErrInternalError`[96]

    Go 1.19对于上述情况,新增了一个更具体的错误 `syntax.ErrNestingDepth`[97],不再返回 `syntax.ErrInternalError`[98]

  • runtime[99]

    `GOROOT`[100] 函数会返回空串,当Go可执行程序使用了-trimpath标记进行编译并且没有在进程运行环境里没有设置GOROOT环境变量。

  • runtime/metrics[101]

    新的 /sched/gomaxprocs:threads 度量指标[102] 会报告 `runtime.GOMAXPROCS`[103] 的当前值。

    新的 /cgo/go-to-c-calls:calls 度量指标[104] 会报告Go调用C的总次数。这个指标等同于 `runtime.NumCgoCall`[105] 函数的执行结果。

    新的 /gc/limiter/last-enabled:gc-cycle 度量指标[106] 在GC CPU limiter开启时,会报告最新的GC循环(cycle)。可以参考runtime notes](https://tip.golang.org/doc/go1.19#runtime) 了解更多关于GC CPU limiter的细节。

  • runtime/pprof[107]

    pprof在收集goroutine profile时做了优化,可以大大减少对应用程序的性能影响。

    所有Unix操作系统上做pprof 的heap profile结果都包含了MaxRSS,之前只有 GOOS=android, darwin, ioslinux系统上才会包含有MaxRSS结果。

  • runtime/race[108]

    race detector在Go 1.19版本做了升级,使用v3版本的 thread sanitizer,支持除了 windows/amd64openbsd/amd64 的所有平台, windows/amd64openbsd/amd64平台仍然使用v2版本的thread sanitizer。

    和v2版本相比,v3版本速度提升了1.5-2倍,并且内存开销减半,还不限制goroutine的数量。

    在Linux操作系统上,race detector现在要求glibc的版本最低是2.17。

    race detector现在支持GOARCH=s390x架构。

    新版的thread sanitizer不再支持openbsd/amd64平台,因此openbsd/amd64平台还是会沿用旧的v2版本的thread sanitizer。

  • runtime/trace[109]

    当tracing和 CPU profiler[110] 同时开启时,tracing也会记录CPU Profile采样的结果。

  • sort[111]

    Go自带的排序算法使用了pattern-defeating quicksort[112]进行重写,速度更快。

    新的函数 Find[113] 类似 函数Search[114] ,但是更好用。Find函数会额外返回一个bool值,用于表示是否找到了相同的数。

  • strconv[115]

    `Quote`[116] 函数和相关函数为了和其它ASCII码值保持一致,会引用字符U+007F为\x7f,而不是\u007f

  • syscall[117]

    对于PowerPC (GOARCH=ppc64, ppc64le)架构,`Syscall`[118]`Syscall6`[119]`RawSyscall`[120],和 `RawSyscall6`[121] 函数的第2个返回值r2 现在永远返回0,而不是之前的未定义值(undefined value)。

    对于AIX和Solaris系统,可以使用 Getrusage 函数了。

  • time[122]

    新方法 `Duration.Abs`[123] 可以得到duration的绝对值,更方便和安全,其中对于边界情况,−2⁶³ 会被转换为 2⁶³−1。

    新方法 `Time.ZoneBounds`[124] 可以返回指定时间所在时区的开始和结束时间。

推荐阅读

想了解Go泛型的使用方法、设计思路和最佳实践,推荐大家阅读

想了解Go原子操作和使用方法,推荐大家阅读

开源地址

文章和示例代码开源在GitHub: Go语言初级、中级和高级教程[125]

公众号:coding进阶。关注公众号可以获取最新Go面试题和技术栈。

个人网站:Jincheng's Blog[126]

知乎:无忌[127]

福利

我为大家整理了一份后端开发学习资料礼包,包含编程语言入门到进阶知识(Go、C++、Python)、后端开发技术栈、面试题等。

关注公众号「coding进阶」,发送消息 backend 领取资料礼包,这份资料会不定期更新,加入我觉得有价值的资料。还可以发送消息「进群」,和同行一起交流学习,答疑解惑。

References

  • https://tip.golang.org/doc/go1.19
78240Go 1.19要来了,看看都有哪些变化-第4篇

这个人很懒,什么都没留下

文章评论