关于go:Go-将增加内置的零值标识符-zero

37次阅读

共计 3037 个字符,预计需要花费 8 分钟才能阅读完成。

大家好,我是煎鱼。

大家学习和应用 Go 语言时,有一个神奇的概念:零值(zero-values)。零值这个名字是具体谁起的,又是从哪里先开始喊起的,曾经难以讲究了。

每次有新同学刚开始转语言,工程上总会提到这个,想要试图扭转零值。又或是没思考到,一旦程序用了 0 作为 default 值,又要兼容零值的问题。

明天给大家分享一个对于零值的新提案,目测曾经八九不离十了。

疾速温习零值

根底类型的例子如下:

func main() {
    var i int
    var f float64
    var b bool
    var s string
    fmt.Printf("%v %v %v %q\n", i, f, b, s)
}

输入后果:

0 0 false ""

复合类型的例子如下:

type Person struct {
    Name   string
    Age    int
    Weight float64
}

func main() {
    var p Person
    var m map[int]string
    var s []string

    fmt.Printf("%#v\n%#v\n%#v\n", p, m, s)
}

输入后果:

main.Person{Name:"", Age:0, Weight:0}
map[int]string(nil)
[]string(nil)

类型和零值的映射表格如下:

数据类型 零值
int, int8, int16, int32, int64 0
uint, uint8, uint16, uint32, uint64 0
uintptr 0
float32, float64 0
byte 0
rune 0
string “” (empty string)
complex64, complex128 (0,0i)
arrays of non-nillable types array of zero-values
arrays of nillable types array of nil-values

新提案:预申明标识符 zero

背景

事件的起因是:@Nathan Cormier 在社区提了吐槽和提案《proposal: builtin: zero function》:

他示意:Go 语言目前提供了几种获取类型零值的办法,如果能有一种对立的办法来实现这一点,代码的可读性会更高。

有同学沉思,哪来的几种?其实能够:

var z MyType
return z

还能够:

return *new(MyType)

初始化构造体后进去的都是零值。

紧接着就会遇到结尾提到的问题,你怎么晓得这是零值,还是缺省值?难以间接判断。

更重要的是,这不太合乎 Go 的设计哲学,又是多种路径,还和缺省值产生混同。显然和主打工程的 Go 的倒退路子不合。

解决方案

新增 zero 标识符

这次通过一番撕扯,最终是由 Go 外围团队负责人 @Russ Cox 进去主持大局,提出了新提案并一路向前。

Go 将会减少一个新的预约义标识符 zero,它是一个无类型的零值 ,实用于数组和构造体类型。

以下是 zero 的类型签名:

// zero is a predeclared identifier representing the zero value
// for array and struct types.
var zero Type

他不会像 nil 一样。咱们能够对照看看 nil 的类型签名:

// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

Nil 受限于 chan、func、interface、map、slice、pointer 等类型。

zero 可赋值性规定

zero 的可赋值性规定如下:

  • 绝大部分场景下,zero 能够调配给任何类型 T 的任何变量。(T 指的是构造体)
  • 不能够的场景,曾经具备短零(指的是:0、“”、nil)的变量,不能够调配。
  • 泛型场景下,即便 T 是带有 any 约束条件的类型参数,也是能够调配的。
  • 上述提到的可赋值性,蕴含函数参数和返回值,例如:f(zero)return zero, err 也是失常无效的,也可能用于值比拟。

可能会有的同学放心,zero 和短零(0, “”, or nil)产生抵触。对此能够释怀。在设计的规定上:zero 在短零无效的任何中央都有效,所以在应用上不会产生混同。

解决了什么问题

理论问题上,解决了以下几点:

  • 在通用代码中须要援用零值,发现大家常常倡议应用 *new(T) 来做初始化。导致常常要向新用户解释这一点十分麻烦。Go 须要更简洁的办法。
  • 在泛型代码中便于与零值比拟,在 cmp: add Or 中呈现了这一理论编码诉求。
  • 缩短谬误返回,新的 return zero, err 会比原有的 return time.Time{}, err 更好。

通用概念来讲:

  • 零值是 Go 中的一个重要概念。但某些类型对此还没有具体的名称,当初能够叫他 zero
  • Go 须要一个机制来将其值和零值进行比拟,来解决前文提到的缺省值和零值无奈很好辨认的问题。

一些问题和争执

会有同学认为,现有的 return _, _, err 会比 return zero, zero, err 更短并且感觉更好。(但在清晰水平上会不如 zero 和 nil)

也有同学会认为本人写一个这个实现也很简略,是否有必要为此专门减少一个 zero 预约义值?

能够用泛型如下实现:

func Zero[T any]() T {
    var v T
    return v
}

对此在很多提案上,都很容易陷入怪圈。有了泛型后,照实现来讲,什么都能够本人写一份。

也会有一派认为当前判断谬误类型要变成:

if err != zero {...}

会十分奇怪。当前可能会呈现 if err != nilif err != zero 的奇怪代码场景。

注:这个场景是假设 zero 标识符能实用于所有的数据类型下才会呈现。本次并不存在。

总结

目前的社区探讨比拟发散,认为 zero 标识符将来也能够取代所有的零值。但从提案内容和提交的 SPEC CL 来看,@Russ Cox 始终针对的是数组和构造体的零值场景去应用 zero 标识符。

这个提案曾经进入到最终阶段,大概率是跑不掉的了。当前咱们在不同类型下对零值判断,能够基于:

数据类型 应用什么作为零值
int 等数字类型 应用 0
string 字符串类型 应用”“(空字符串)
slice, map, function, pointer, channel, and interface 等类型 应用 nil
array 和 struct 类型 可应用 zero 标识符

尽管在应用上,做了肯定的应用场景的切分,也就是只有数组和构造体类型应用 zero 标识符。但对于写 Go 用户而言,认知上是会存在明确混同的。

当前你给其他同学解释零值,解释起得辨别两种场景来介绍。我感觉还不如 zero 标识符一统零值天下。但很惋惜,本次提案临时并没有这个打算。

文章继续更新,能够微信搜【脑子进煎鱼了】浏览,本文 GitHub github.com/eddycjy/blog 已收录,学习 Go 语言能够看 Go 学习地图和路线,欢送 Star 催更。

Go 图书系列

  • Go 语言入门系列:初探 Go 我的项目实战
  • Go 语言编程之旅:深刻用 Go 做我的项目
  • Go 语言设计哲学:理解 Go 的为什么和设计思考
  • Go 语言进阶之旅:进一步深刻 Go 源码

举荐浏览

  • Go 团队将批改 for 循环变量的语义,Go1.21 新版本即可体验!
  • Go1.21 速览:Context 能够设置勾销起因和回调函数了,等的可太久了!
  • Go1.21 速览:过了一年半,slices、maps 泛型库终于要退出规范库。。。

正文完
 0