我正在阅读以下文章:
https://www.ribice.ba/golang-enums/
在其中一个代码示例中定义了一个函数:
func (lt *LeaveType) UnmarshalJSON(b []byte) error {
// Define a secondary type to avoid ending up with a recursive call to json.Unmarshal
type LT LeaveType;
var r *LT = (*LT)(lt);
err := json.Unmarshal(b, &r)
if err != nil{
panic(err)
}
switch *lt {
case AnnualLeave, Sick, BankHoliday, Other:
return nil
}
return errors.New("Inalid leave type")
}
var r *LT = (*LT)(lt);
的语法是什么在这个例子中做什么?
最佳答案
从技术上讲,Go 没有强制转换,而是转换。显式转换的语法是 T(x)
在哪里 T
是某种类型和x
是可转换为该类型的某个值。见 Conversions in the Go specification详情。
从函数的声明中可以看出:
func (lt *LeaveType) UnmarshalJSON(b []byte) error {
lt
本身具有指向 LeaveType
的类型指针和 UnmarshalJSON
是 *LeaveType
类型的接收器函数. encoding/json
当包要设置的变量的类型为 LeaveType
时,包将调用这样的函数来解码输入 JSON (或 *LeaveType
— 在这种情况下,包将自行创建 LeaveType
变量)。正如代码中的注释所说,代码的作者现在想要
encoding/json
代码解码 JSON,就好像没有函数 UnmarshalJSON
.但是有一个功能UnmarshalJSON
,所以如果我们只调用 encoding/json
没有一点技巧的代码,encoding/json
只会再次调用这个函数,导致无限递归。通过定义新类型
LT
其内容与现有类型 LeaveType
完全相同,我们最终得到了一个没有接收函数的新类型。调用 encoding/json
在这种类型的实例(或指向这种类型的指针)上不会调用 *LeaveType
接收者,因为 LT
是一个不同的类型,即使它的内容完全匹配。我们可以这样做:
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
设置*lt
:*lt = LeaveType(r) // an ordinary conversion
之后我们可以像以前一样继续使用
*lt
作为值(value)。但这意味着 UnmarshalJSON
必须设置一个临时变量 r
,然后我们必须将其复制到其最终目的地。为什么不设置一些东西,以便 UnmarshalJSON
填写目标变量,但是使用我们选择的类型?这就是这里的语法。这不是最短的版本:正如 Cerise Limón 所指出的,有一种更短的拼写方式(通常首选更短的拼写方式)。
(*LT)(lt)
中的第一组括号需要绑定(bind) *
——指向部分的指针——指向 LT
,如 *LT(lt)
绑定(bind)错误:与 *(LT(lt))
含义相同这不是我们想要的。
关于json - Golang 中的类型转换,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60440743/