Go技术上没有casts反而转换。显式转换的语法是T(x)
where T
是某种类型并且x
是可转换为该类型的某个值。看Go 规范中的转换了解详情。
从函数的声明中可以看出:
func (lt *LeaveType) UnmarshalJSON(b []byte) error {
lt
本身有类型指向LeaveType
and UnmarshalJSON
is a 接收函数对于类型*LeaveType
. The encoding/json
当包想要设置的变量具有类型时,包将调用这样的函数来解码输入 JSONLeaveType
(or *LeaveType
- 该包将创建LeaveType
在这种情况下变量本身)。
正如代码中的注释所说,代码的作者现在希望拥有encoding/json
代码解组 JSONas if没有函数UnmarshalJSON
。但有is一个函数UnmarshalJSON
,所以如果我们只是调用encoding/json
没有一点欺骗的代码,encoding/json
只会再次调用该函数,导致无限递归。
通过定义一个new type LT
其内容与现有类型完全相同LeaveType
,我们最终得到一个新类型does not具有接收功能。调用encoding/json
在此类型的实例(或指向该类型的指针)上won't打电话给*LeaveType
接收器,因为LT
是一种不同的类型,尽管它的contents完全匹配。
我们可以这样做:
func (lt *LeaveType) UnmarshalJSON(b []byte) error {
type LT LeaveType
var r LT
err := json.Unmarshal(b, &r)
if err != nil {
panic(err)
}
// ...
}
这将填写r
,其大小和形状与任何LeaveType
多变的。然后我们就可以使用填好的r
to set *lt
:
*lt = LeaveType(r) // an ordinary conversion
之后我们可以像以前一样继续使用*lt
作为值。但这意味着UnmarshalJSON
必须设置一个临时变量r
,然后我们必须将其复制到其最终目的地。为什么不相反,设置一些东西,以便UnmarshalJSON
填充目标变量,但是使用我们选择的类型?
这就是这里的语法for。这不是shortest版本:正如 Cerise Limón 所指出的,有一种更短的拼写方式(并且通常首选较短的拼写)。第一组括号(*LT)(lt)
需要绑定*
—the 指向部分——到LT
, as *LT(lt)
绑定错误:它的含义与*(LT(lt))
这不是我们想要的。