谈谈go1.21更新 | 青训营

359 阅读3分钟

就在前几天,go更新了1.21版本,我们来看看大致更新了哪些东西

新增内置函数Max,Min,clear

这三个函数的添加大家已经争论很久了,在1.21终于加上了,终于不用再大量的写max和min了!

    // Min和Max可以接受任意数量的相同数值类型的参数,但是不支持使用 slice 参数
    a := min(1, 2, 3) // a is 1
    b := max(4.5, 6.7, 8.9) // b is 8.9

关于clear大几率是因为map在此之前无法便捷的清空值,需要使用 for-range + delete的方式来清空

那么clear如何使用呢? 函数签名:

func clear[T ~[]Type | ~map[Type]Type1](t T)

它会有如下作用:

  • 对于 map,会将其变为一个空 map。len 属性的值会改变,值为 0 。
  • 对于 slice,会将 slice 或 array 长度内的所有元素设置为相应元素类型的零值。len 属性的值不会改变。
  • 对于泛型的类型参数(type parameter):类型参数的类型集必须只包含 map、slices 或指向数组的指针的类型,clear 函数将会执行实际类型参数所对应的 clear 操作。

演示demo:

 func main() {  
     m := map[string]string{"key1""value1""k2""v2"}  
     fmt.Printf("m1: %v, len: %d\n", m, len(m))  
     clear(m)  
     fmt.Printf("m2: %v, len: %d\n", m, len(m))  
}

输出结果:

 m1: map[key1:value1 k2:v2], len2  
 m2: map[], len0

新增cmp包

1、Nan概念

在在了解这个包之前,我们先来谈谈NaN(Not a Number,非数)这个概念:

在go中,NaN是一个特殊的浮点数值,表示“不是一个数字”(Not a Number)。它通常是由一些无效的数学运算产生的,比如除以0,或者对负数开平方。

NaN有一些特殊的性质,比如:

  • NaN不等于任何值,包括它自己。所以不能用==来判断一个值是否是NaN,而要用math.IsNaN函数。
  • NaN不能被排序,因为它没有大小关系。所以如果一个切片里有NaN,就不能用sort包来排序。
  • NaN不能作为map的键,因为它不可比较。所以如果一个map里有NaN作为键,就不能用delete函数来删除它。

2、cmp中的函数

内置函数及作用:

  • Less:判断 x 是否小于 y。对于浮点类型,NaN 被认为小于任何非 NaN、 而 -0.0 不小于(等于)0.0。
  • Compare:比较 x 和 y,返回对应预定义的枚举值:
    • 如果 x 小于 y,则返回 -1
    • 如果 x 等于 y,则返回 0
    • 如果 x 大于 y,则返回 +1
  • isNaN:判断 x 是否为 NaN。

3、源码

源码也比较简单易懂:

` package cmp  

  type Ordered interface {  
 ~int | ~int8 | ~int16 | ~int32 | ~int64 |  
  ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr |  
  ~float32 | ~float64 |  
  ~string  
}  

func Less[T Ordered](x, y T) bool {  
 return (isNaN(x) && !isNaN(y)) || x < y  
}  

func Compare[T Ordered](x, y T) int {  
 xNaN := isNaN(x)  
 yNaN := isNaN(y)  
 if xNaN && yNaN {  
  return 0  
 }  
 if xNaN || x < y {  
  return -1  
 }  
 if yNaN || x > y {  
  return +1  
 }  
 return 0  
}  

func isNaN[T Ordered](x T) bool {  
 return x != x  
}`

原本max、min、clear都是属于这个包的,但是它们功能比较特殊,所以单独拿了出来

更新了泛型函数的类型判断

 // Before go 1.21, this would cause a compile error: cannot infer T
func Print[T any](s []T) {
        for _, v := range s {
	fmt.Println(v)
            }
}

// After go 1.21, this can compile successfully: T is inferred as int
Print([]int{1, 2, 3})

当然,1.21更新了不只这些,但我也还在研究中