首先请看一下kubernetes core的API代码:https://github.com/kubernetes...
【Kubernetes API规范(为optional的字段使用pointer)】我们可以发现,只要是 optional
的字段,那么必然是一个pointer:
// nfs represents an NFS mount on the host that shares a pod's lifetime
// More info: https://kubernetes.io/docs/concepts/storage/volumes#nfs
// +optional
NFS *NFSVolumeSource `json:"nfs,omitempty" protobuf:"bytes,7,opt,name=nfs"`
再比如:
// volumeMode defines if a volume is intended to be used with a formatted filesystem
// or to remain in raw block state. Value of Filesystem is implied when not included in spec.
// +optional
VolumeMode *PersistentVolumeMode `json:"volumeMode,omitempty" protobuf:"bytes,8,opt,name=volumeMode,casttype=PersistentVolumeMode"`
这是为什么呢?
其实在kubernetes官方给出的API规约中,有这样一句话:https://github.com/kubernetes...
Therefore, we ask that pointers always be used with optional fields that do not have a built-in nil
value.
翻译为:我们要求没有内建
nil
值的optional字段,总是使用pointers.首先我们需要了解使用pointer和没有使用pointer的区别,假设我们没有使用pointer:
type Apple struct {
// +required
Name string `json:"name"`
}type Tree struct {
// +optional
Apple Apple `json:"apple"`
}
当我们想创建一个 “没有苹果的树”, 我们使用put如下json:
{}
但是由于
apple
字段并不是pointer,所以我们最终创建的是一个空结构体,最终存储(在etcd或者disk)的结构为:{
apple: {
name: ""
}
}
但是这个结构也可以表示一个“有苹果的树”,只不过苹果的名字为“”(空字符串)。
此时,“零值(zero value)”和“空(nil)”之间就有了歧义。 虽然我们可以在代码中添加一些规则来消除这种歧义,比如: 禁止创建名字为空字符串的苹果。
但是Kubernetes API规约中,也给出了3点原因,解释我们为什么最好在field是optional的情况下,使用pointer:
- 此类情况很多,实现者每一个都需要甄别和处理的话,过于劳心费神。
- 即使指定了
omitempty
,编码器输出也不会省略结构,最后看起来就会乱糟糟的。 - 如果在客户端代码中使用go编码,且遵守了“optional->pointer”的规则,那么当遇到一个pointer的时候,我们也直接可以反推出这个field是optinal的,十分方便。