预期中的Go 2不会有了,1.20也算是一个小gap,从中可以一窥Go未来的发展之路。对于Go来说,未来保持1.x持续演进和兼容性之外,重点就是让Go性能更优,同时保持大道至简原则,使用尽可能容易,从这两个方面带大家看看你1.20值得关注的特性。
优化相关
编译速度
1.18引入泛型,降低了编译速度,这一般版本基本上优化和1.17平齐,当前1.20的编译也是依赖Go 1.17版本自举。如果没泛型刚需的,可以等到1.20稳定后升级。
内存优化area
引入新的内存分配机制arena,支持手动管理内存,部分场景提升5%-15%,可参考golang新特性arena,带你起飞。
编译优化pgo
全称Profile-guided optimization (PGO),也是一项新的优化技术,通常提升3%-4%,简单说就是先跑一遍程序生成pprof文件,然后基于此文件引导编译器优化再编译一遍。当前只实现内联的优化,后续可能增加多种优化,个人理解有点类似离线版本JIT。
发行体积
安装包安装,$GOROOT/pkg 目录将不再存储标准库的预编译包存档,相比之前减少1/3。
默认禁用 CGO
在没有C toolchain的系统上默认禁用 CGO,相比依赖CGO的标准库,此情况编译只依赖pure Go。
代码编写
可以看到,Go新版本代码编写演进总的原则就是简化写代码的心智负担,普通开发者只需要关心实现即可,尽可能少的和底层实现绑定。
多error wrap
在1.13基础上,增加多error wrap的能力,类似功能不用再依赖外部库(hashicorp/go-multierror库等)。
使用很简单,如下,多个%w格式化即可wrap,同时支持Is和As
func TestMultiWrap(t *testing.T) {
err1 := errors.New("Error 1")
err2 := errors.New("Error 2")
err3 := errors.New("Error 3")
err := fmt.Errorf("%w,%w,%w", err1, err2, err3)
fmt.Printf("wrap errors:%v\n", err)
fmt.Printf("is err1:%v, is err2:%v, is err3:%v\n",
errors.Is(err, err1),
errors.Is(err, err2),
errors.Is(err, err3))
}
输出
wrap errors:Error 1,Error 2,Error 3
is err1:true, is err2:true, is err3:true
slice转array
在1.20之前,slice转array需要了解底层原理,如下实现,不是特别直观
slice := []int{1, 2, 3, 4, 5}
// 老方法
array1 := *(*[5]int)(slice)
1.20引入直接转换实现,降低新手入门难度,更加直观,如下操作即可
//新方法
// 1.20之前报错 cannot convert slice (variable of type []int) to type [5]int
array2 := [5]int(slice)
//array22 := [6]int(slice)
//fmt.Printf("Array:%v\n", array22)
注意目标数组长度不能大于slice长度,否则报错
// panic: runtime error: cannot convert slice with length 5 to array or pointer to array with length 6
bytes string互转
在1.20之前,bytes/string互转需要了解底层实现,借助unsafe代码来实现如下
func OldBytesToString(b []byte) string {
return *((*string)(unsafe.Pointer(&b)))
}
func OldStringToBytes(s string) []byte {
stringHeader := (*reflect.StringHeader)(unsafe.Pointer(&s))
var b []byte
pbytes := (*reflect.SliceHeader)(unsafe.Pointer(&b)) // 先引用,防止原有string gc
pbytes.Data = stringHeader.Data
pbytes.Len = stringHeader.Len
pbytes.Cap = stringHeader.Len
return b
}
1.20中,官方提供如下三个函数包装下底层实现
- func String(ptr *byte, len IntegerType) string:根据数据指针和字符长度构造一个新的 string。
- func StringData(str string) *byte:返回指向该 string 的字节数组的数据指针。
- func SliceData(slice []ArbitraryType) *ArbitraryType:返回该 slice 的数据指针。
以往常用的 reflect.SliceHeader 和 reflect.StringHeader 将会被标注为被废弃。
互转代码大大简化,可如下实现
func NewBytesToString(b []byte) string {
return unsafe.String(&b[0], len(b))
}
func NewStringToBytes(s string) []byte {
return unsafe.Slice(unsafe.StringData(s), len(s))
}
时间格式化和比较
在1.20之前,时间格式化只能用别扭的2006-01-02 15:04:05语法,可能创始人觉得Geek吧,扛不住刚需,现在终于支持常见的如下三种格式化语法,不知道啥时候能把YYmmdd加进来
func TestTimeFormat(t *testing.T) {
tm1 := time.Now()
fmt.Printf("DateTime-%v\nDateOnly-%v\nTimeOnly-%v\n",
tm1.Format(time.DateTime),
tm1.Format(time.DateOnly),
tm1.Format(time.TimeOnly))
}
输出
DateTime-2023-02-09 00:43:13
DateOnly-2023-02-09
TimeOnly-00:43:13
另外就是,相比之前的After/Before比较,新引入一个Compare方法,比较上更加直观和方便文章来源:https://www.toymoban.com/news/detail-442017.html
func TestTimeCompare(t *testing.T) {
tm1 := time.Now()
tm2 := time.Now()
c := tm1.Compare(tm2)
if c == -1 {
fmt.Println("tm1 < tm2")
} else if c == 0 {
fmt.Println("tm1 = tm2")
} else if c == 1 {
fmt.Println("tm1 > tm2")
}
}
参考
代码 https://gitee.com/wenzhou1219/go-in-prod/tree/master/go_120_feature文章来源地址https://www.toymoban.com/news/detail-442017.html
- Go1.20 那些事:错误处理优化、编译速度提高、PGO 提效等新特性,你知道多少?
- Go 1.20 is released! - The Go Programming Language
- What’s New in Go 1.20, Part I: Language Changes
- Exploring Go’s Profile-Guided Optimizations
- PGO 是啥,咋就让 Go 更快更猛了?
- GopherCon 2022: Russ Cox - Compatibility: How Go Programs Keep Working: https://www.youtube.com/watch?v=v24wrd3RwGo
到了这里,关于golang 1.20正式发布,更好更易更强的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!