json.Unmarshal() 将一些 JSON 文本解组为 Go 值。如果要解组的值实现了json.Unmarshaler 接口,则调用其UnmarshalJSON() 方法,该方法允许实现自定义解组逻辑。
引用json.Unmarshal():
为了将 JSON 解组为实现 Unmarshaler 接口的值,Unmarshal 调用该值的 UnmarshalJSON 方法,包括当输入为 JSON null 时。
json.Unmarshaler 接口:
type Unmarshaler interface {
UnmarshalJSON([]byte) error
}
LeaveType(或更具体地说是*LeaveType)有一个UnmarshalJSON() 方法,我们可以在问题中看到,所以它实现了json.Unmarshaler。
LeaveType.UnmarshalJSON() 方法希望使用 default 解组逻辑,该逻辑执行“硬”部分,并且只想进行一些最终调整。所以它调用json.Unmarshal():
err := json.Unmarshal(b, &r)
如果我们将lt 传递给unmarshal 到,--因为lt 实现json.Unmashaler--LeaveType.UnmarshalJSON() 将被json 包调用,有效地导致无限“递归”。
当然,这不是我们想要的。为了避免无限递归,我们必须传递一个没有实现json.Unmarshaler的值,该值的类型没有UnmarshalJSON()方法。
这就是创建新类型的地方:
type LT LeaveType
type 关键字创建了一个名为 LT 的新类型,它不同于 LeaveType。它不会“继承”任何LeaveType 的方法,因此LT 不会实现json.Unmarshaler。因此,如果我们将LT 或*LT 的值传递给json.Unmarshal(),则不会导致LeaveType.UnmarshalJSON() 被调用(通过json 包)。
var r *LT = (*LT)(lt)
这声明了一个名为r 的变量,其类型为*LT。并将值lt 转换为*LT。需要进行转换,因为lt 的类型为*LeaveType,因此不能将其分配给*LT 类型的变量,但由于LT 具有LeaveType 作为其基础类型,*LeaveType 可以转换为@ 987654368@.
所以r 是一个指针,它指向与lt 相同的值,它具有相同的内存布局。因此,如果我们使用默认的解组逻辑并“填充”r 指向的结构,那么将填充lt 指向的“相同”结构。
查看相关/类似问题:Call json.Unmarshal inside UnmarshalJSON function without causing stack overflow