Golang1.21语言特性更新
目录
新增内置函数⌗
min和max⌗
相关issue:https://github.com/golang/go/issues/59488
在builtin.go中的函数定义如下(实际的实现在runtime中,通过编译器的配合实现调用):
// The max built-in function returns the largest value of a fixed number of
// arguments of [cmp.Ordered] types. There must be at least one argument.
// If T is a floating-point type and any of the arguments are NaNs,
// max will return NaN.
func max[T cmp.Ordered](x T, y ...T) T
// The min built-in function returns the smallest value of a fixed number of
// arguments of [cmp.Ordered] types. There must be at least one argument.
// If T is a floating-point type and any of the arguments are NaNs,
// min will return NaN.
func min[T cmp.Ordered](x T, y ...T) T
哪些类型符合cmp.Ordered呢?可以通过go doc cmp.Ordered查看
type Ordered interface {
~int | ~int8 | ~int16 | ~int32 | ~int64 |
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |
~float32 | ~float64 |
~string
}
clear⌗
相关issue: https://github.com/golang/go/issues/56351
builtin.go中的函数定义如下:
// The clear built-in function clears maps and slices.
// For maps, clear deletes all entries, resulting in an empty map.
// For slices, clear sets all elements up to the length of the slice
// to the zero value of the respective element type. If the argument
// type is a type parameter, the type parameter's type set must
// contain only map or slice types, and clear performs the operation
// implied by the type argument.
func clear[T ~[]Type | ~map[Type]Type1](t T)
只有map和slice类型才能调用clear函数,如果是类型参数,那么类型参数的类型集合必须只包含map或者slice类型。
但是map和slice处理方式不同
- clear map:删除所有的键值对,map变成空map,但并未释放掉这些键值所占用的内存。(关于map内存释放的问题,另有一个open的issue)
- clear slice:将保持slice的长度和容量,但是所有值都被置为零值。
明确了包初始化顺序⌗
类型推导(type inference)增强⌗
具体可见Go1.21类型推断增强
loop variables per-iteration替代per-loop⌗
相关issue:
相关wiki:
Go团队可能会在Go1.22中将loop variables per-iteration替代per-loop,这是一个breaking change,如果你的代码中有类似以下的代码,那么你的代码可能会受到影响。
var m = map[string]int{"a": 1, "b": 2}
for k, v := range m {
go func() {
time.Sleep(1 * time.Second)
fmt.Printf("k: %v, v: %v\n", k, v)
}()
}
以上这段代码正常执行会输出
k: b, v: 2 k: b, v: 2
loop var的变量k, v在每个loop中都指向同一个,所以在goroutine中打印的k, v都是最后一次循环的值。
如果想要每次goroutine中每次输出的值为对应loop的k, v值,那么有以下两种规避的方法。
方法1: 给goroutine闭包传参
for k, v := range m {
go func(k string, v int) {
time.Sleep(1 * time.Second)
fmt.Printf("k: %v, v: %v\n", k, v)
}(k, v)
}
方法2: 在每个loop内使用本地变量
for k, v := range m {
var k1, v1 = k, v
go func() {
time.Sleep(1 * time.Second)
fmt.Printf("k: %v, v: %v\n", k1, v1)
}()
}
Go1.22可能会改变当前默认行为(实际情况要等到1.22发布),让上面例子中每个loop的k, v都是单独分配的。而在Go1.21中,可以使用GOEXPERIMENT=loopvar
。
panic(nil)⌗
相关issue:
func main() {
defer func() {
if err := recover(); err != nil {
fmt.Println("panic:", err)
return
}
fmt.Println("ok")
}()
panic(nil)
}
在Go1.20中,上面的代码会打印出
ok 而在Go1.21中,上面的代码会打印出 panic: panic called with nil argument
在Go1.21中,编译器会自动将panic(nil)
替换为panic(new(runtime.PanicNilError))
。
这是个breaking change,如果你的代码中有panic(nil)
,并想保留原有的行为,那么可以使用GODEBUG=panicnil=1
。