golang1.14于2月25日发布,到现在已经差不多3周了。本文主要对1.14中的一些新特性做简要的解读。与以前的1.X版本一样,1.14保持向前兼容,所有现存的golang程序无需任何修改,应该可以继续在golang1.14上编译并运行。


Module(模块)

Module并不是golang1.14新引入的特性。它在1.11就引入了,在1.13中默认enable。但是直到1.14,官方才明确声称对Module的支持"ready for production use",并鼓励所有用户迁移到Module来管理依赖。


go命令行围绕Module也做了一些更新。在golang 1.13中,如果命令行带参数"-mod=vendor",那么就会认为依赖项保存在vendor子目录中。在golang 1.14中,只要Module的根目录下包含一个vendor子目录,就默认按照命令行参数中已经有参数"-mod=vendor"来处理,除非明确在命令行指定"-mod=mod"。


另外,增加了一个新的命令行选项"-modfile=file"。可以指定一个文件来替代默认的go.mod。例如"-modfile=abc.mod",就会从abc.mod中读取或写入依赖项信息,而不是默认的go.mod。相应的,默认的go.sum也会被abc.sum替代。


GOINSECURE是一个新增的环境变量,用来设置获取哪些第三方Module不需要HTTPS连接。这样就无需校验证书信息。与GOPRIVATE类似,如果设置一个列表,用逗号分隔每个URL。


Permit embedding of Interfaces with overlapping method sets

在以前的golang interface规范中,要求interface中每一个方法必须有一个非空且唯一的名字。因为golang支持在一个interface中内嵌其它的interface,相当于C++/Java中的继承或实现,这样就很容易形成钻石(或称为菱形)的“继承”结构。例如:

  type ReadWriteCloser interface {
io.ReadCloser
io.WriteCloser
}


io.ReadCloser与io.WriteCloser都内嵌了Closer接口,

type Closer interface {
    Close() error
}


所以ReadWriteCloser里面就包含了两个重复的Close方法定义。根据golang以前的规范,这样是非法的。而这又是很常见的一种设计。所以在golang 1.14中,对golang interface的规范做了修改,使这种设计合法。但有一个条件,那就是重复方法的签名必须完全一样,包含方法名、参数、返回值完全一样。例如下面这个就是非法的,因为重复方法m的参数类型不同,

type E1 interface { m(x int) bool }
type E2 interface { m(x float32) bool }
type I interface { E1; E2 } // invalid since E1.m and E2.m have the same name but different signatures


另外,与以前一样,还是不允许在一个interface中重复申明一样的方法,

type I interface {
m()
m() // invalid; m was already explicitly declared
}


Ports(移植兼容性)

Golang 1.14是最后一个支持macOS 10.11 EI Capitan的版本,从Golang 1.15开始,支持的最低版本将是macOS 10.12 Sierra。Golang 1.14也是最后一个支持macOS 32-bit binaries的版本。


对于iOS,IPadOS,watchOS和tvOS来说,Golang 1.14也很可能是最后一个支持32-bit binaries的版本。


运行在Windows平台的Go binaries已经enable了DEP(Data Execution Prevention)。

https://docs.microsoft.com/en-us/windows/win32/memory/data-execution-prevention


通过js.Value引用的JavaScript的值现在也可以被垃圾回收了,但是不能通过==来比较这些值,只能通过Equal方法来比较。


Golang 1.14开始支持 64-bit RISC-V on Linux以及64-bit ARM on FreeBSD 12.0+,编译时指定下面的环境变量:

GOOS=linux GOARCH=riscv64
GOOS=freebsd GOARCH=arm64

但要注意,对RISC-V的支持还处于实验阶段,所以谨慎使用该特性。


Golang 1.14已经放弃了对Native Client Platform的支持,

GOOS=nacl


Golang 1.14 runtime开始支持IIIumos平台的虚拟化技术Zone。runtime.NumCPU以及GOMAXPROCS的默认值都会受影响。


Runtime(运行时)

Golang 1.14的 runtime也有很多的优化。首先是defer的性能进一步的提高,与直接函数调用相比,defer号称是zero overhead。


Goroutine开始可以被异步抢占,这就意味着一个没有函数调用的循环,不会再导致可能潜在的调度器的死锁,或者垃圾回收的严重延迟。


页面分配算法更有效,在并发环境下(GOMAXPROCS值更大的情况)极大的减少了相互的互斥竞争。定时器的内部实现效率也更高。

Library(库)

首先,Golang 1.14引入了一个新包 "hash/maphash"。可以对任意字符串(string)或字节序列(byte sequence)进行hash运算,得到一个unsigned 64-bit的整数。具体参考:

https://golang.org/pkg/hash/maphash/
https://golang.org/src/hash/maphash/maphash.go


关于hash/maphash,有两点要特别注意:

  • 一个Hash结构在并发访问的场景下,是不安全的,也就是不能被多个goroutine并发访问。但一个Seed对象在并发环境下是安全的。

  • 在同一个进程中,对一个byte sequence进行hash运算的结果是稳定一致的,但多个进程下,则可能会得到不同的值。


其次,对现在的一些package也做了一些minor的改动,比如crypto/tls删除了对SSLv3的支持等等。这里就不一一罗列。


Reference

https://golang.org/doc/go1.14

https://github.com/golang/proposal/blob/master/design/6977-overlapping-interfaces.md

https://golang.org/pkg/hash/maphash/

https://golang.org/src/hash/maphash/maphash.go

https://docs.microsoft.com/en-us/windows/win32/memory/data-execution-prevention


--END--