Golang Inside
首发于Golang Inside
Golang 1.10 前瞻

Golang 1.10 前瞻

Golang 1.10 beta 今天正式 release 了,Golang 1.10 正式发布将在 2018 年 2 月份,我们不妨先来看一下 1.10 的特性。大家可以从这个链接 go1.10 beta 进行下载安装。验证输出如下就是安装成功了。

➜  ~ go version
go version go1.10beta1 darwin/amd64

如果你现在机器上已经安装了其他版本,可以通过下面方式来体验。

$ go get golang.org/x/build/version/go1.10beta1
$ go1.10beta1 download

使用的时候用 go1.10beta1 替换之前的 go 命令即可。我们下面看一下 Go 1.10 的主要特性。

1. 兼容性

语言本身依然向前兼容,操作系统和上一个版本也没有区别。值得注意的是 Go 1.10 将是最后一个可以运行在 OS X 10.8 的版本,Go 1.11 要求 OS 系统为 10.9 以及更新的系统。其他操作系统要求在 Go 1.11 也有调整。

2. 工具链

1. Build & Install

现在 build 的时候基于最新的源码来进行编译。

2. Test

Test 会将结果进行缓存。我觉得这不见得是一个好的机制。

另外执行 go test 会自动执行 go vet。

3. Diagnostics

新增overview of available Go program diagnostic tools.

3. Runtime

LockOSThreadUnlockOSThread 锁的行为现在是可嵌套的(nested)。这两个函数的作用是将 goroutine 绑定到特定的操作系统线程上,之前的 go 版本的行为是多次 Lock 等同于一次 Lock,所以不管调用多少次 Lock 只要调用了一次 Unlock 就会达到解锁的目的。

另外GOMAXPROCS的设置目前没有限制了。(在 1.9 的时候限制为 1024)。

4. Performance

略有提升。

5. GC

微调。

6. 标准库

标准库的改动都比较小,涉及改动的 package 包括 crypto, encoding 等,下面介绍几个我觉得值得关注的改动。

1. bytes

bytes 里面的函数 Fields,FieldsFunc,Split,SplitAfter (函数原型如下)返回的 subslice 是指向原来的 slice 的地址,以及沿用之前的 capacity。1.10 版本返回的 subslice 也是指向原来的地址空间,但是 capacity 调整为 subslice 一样大小,这样对返回的 subslice 进行 append 操作的时候就会进行内存的重新分配,不会影响到别的 subslice。

func Fields(s []byte) [][]byte {...}

示例代码: Go 1.10 beta。

package main

import (
    "bytes"
    "fmt"
)

func main() {
    str := []byte("Hello world")
    fields := bytes.Fields(str)
    fmt.Printf("filed0 cap: %d. field1 cap: %d.\n", len(fields[0]), len(fields[1]))
    _ = append(fields[0], 'X', 'Y')
    fmt.Printf("old string: %s. field0: %s. field1: %s.\n", string(str), fields[0], fields[1])
}

输出结果:

➜  go go run bytes_fields.go
filed0 cap: 5. field1 cap: 5.
old string: Hello world. field0: Hello. field1: world.

之前版本的输出结果如下

➜  go go run bytes_fields.go
filed0 cap: 16. field1 cap: 10.
old string: HelloXYorld. field0: Hello. field1: Yorld.

2. go/doc

使用 go doc 查看 T 类型的时候,也会返回返回值为 T, *T, **T 的 slice 的函数。

$ go doc mail.Address
package mail // import "net/mail"

type Address struct {
	Name    string 
	Address string
}
    Address represents a single mail address.

func ParseAddress(address string) (*Address, error)
func ParseAddressList(list string) ([]*Address, error)
func (a *Address) String() string

3. strings

strings 包增加新类型 Builder,可以用来连接字符串。

// A Builder is used to efficiently build a string using Write methods.
// It minimizes memory copying. The zero value is ready to use.
type Builder struct {
	buf []byte
}

// String returns the accumulated string.
func (b *Builder) String() string {
	return *(*string)(unsafe.Pointer(&b.buf))
}

// Len returns the number of accumulated bytes; b.Len() == len(b.String()).
func (b *Builder) Len() int { return len(b.buf) }

// Reset resets the Builder to be empty.
func (b *Builder) Reset() { b.buf = nil }

连接 byte。

// WriteByte appends the byte c to b's buffer.
// The returned error is always nil.
func (b *Builder) WriteByte(c byte) error {
	b.buf = append(b.buf, c)
	return nil
}

连接 string。

// WriteString appends the contents of s to b's buffer.
// It returns the length of s and a nil error.
func (b *Builder) WriteString(s string) (int, error) {
	b.buf = append(b.buf, s...)
	return len(s), nil
}

4. strconv

现在 strconv 的 ParseUint 函数如果是 ErrRange 错误就返回上确界,以前返回的是 0。

package main

import (
    "strconv"
    "fmt"
)

func main() {
    fmt.Println(strconv.ParseUint("1234", 10, 10))
    // output: 1024
    fmt.Println(strconv.ParseUint("1234", 10, 11))
    // output: 1234
} 

5. net/smtp

Client 增加探活函数:Noop。

6. net/url

ResolveReference 函数现在会保留 url 里面的所有反斜杠,之前的版本会把 host 之后的反斜杠合并为一个,这样有时候会导致 redirect 不准确。

package main

import (
    "net/url"
    "fmt"
)

func main() {
    base, _ := url.Parse("http://host//path//to//page1")
    target, _ := url.Parse("page2")
    fmt.Println(base.ResolveReference(target))
}

Go 1.10 输出为: host//path//to//page2, 老版本输出为 http://host/path//to//page2

编辑于 2017-12-09

文章被以下专栏收录