Golang中的类型转换 [英] Typecasting in Golang
问题描述
我正在阅读以下文章: 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
是可转换为该类型的某些值.有关详细信息,请参见 Go规范中的转化.
从函数的声明中可以看到:
func (lt *LeaveType) UnmarshalJSON(b []byte) error {
lt
本身具有指向LeaveType
的指针类型,而UnmarshalJSON
是类型*LeaveType
的接收器函数.当encoding/json
包要设置的变量的类型为LeaveType
(或*LeaveType
,在这种情况下,包将自行创建LeaveType
变量)时,encoding/json
包将调用该函数来解码输入的JSON.
正如代码中的注释所表明的那样,代码的作者现在想让encoding/json
代码解组JSON 的字符串,就好像中没有函数UnmarshalJSON
一样.但是这里有 函数UnmarshalJSON
,因此,如果我们只是调用encoding/json
代码而没有一点点麻烦,那么encoding/json
就会再次调用此函数,从而导致无限递归.>
通过定义其内容与现有类型LeaveType
完全相同的 new 类型LT
,我们最终得到一个没有的新类型接收器功能.在此类型的实例(或指向该类型的指针)上调用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
作为值.但这意味着UnmarshalJSON
必须设置一个临时变量r
,然后我们必须将其复制到其最终目的地.相反,为什么不做一些设置,以便UnmarshalJSON
填写目标变量,但使用我们选择的类型?
这就是 for 的语法.它不是最短版本:正如CeriseLimón指出的那样,它的拼写方式更短(通常首选较短的拼写方式).必须将(*LT)(lt)
中的第一组括号绑定到LT
,因为*LT(lt)
具有错误的绑定:将*
(指向指向的指针部分)绑定到LT
:这意味着同一件事*(LT(lt))
,这不是我们想要的.
I was reading this following article: https://www.ribice.ba/golang-enums/
There is a function defined in one of the code samples:
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")
}
What is the syntax var r *LT = (*LT)(lt);
doing in this example?
Go technically does not have casts but rather conversions. The syntax for an explicit conversion is T(x)
where T
is some type and x
is some value that is convertible to that type. See Conversions in the Go specification for details.
As you can see from the function's declaration:
func (lt *LeaveType) UnmarshalJSON(b []byte) error {
lt
itself has type pointer to LeaveType
and UnmarshalJSON
is a receiver function for type *LeaveType
. The encoding/json
package will call such a function to decode input JSON when the variable that the package would like to set has type LeaveType
(or *LeaveType
—the package will create the LeaveType
variable itself in this case).
As the comment in the code says, the author of the code would now like to have the encoding/json
code unmarshal the JSON as if there weren't a function UnmarshalJSON
. But there is a function UnmarshalJSON
, so if we just invoke the encoding/json
code without a little bit of trickery, encoding/json
will just call this function again, leading to infinite recursion.
By defining a new type LT
whose contents are exactly the same as the existing type LeaveType
, we end up with a new type that does not have a receiver function. Invoking the encoding/json
on an instance of this type (or of a pointer to this type) won't call the *LeaveType
receiver, because LT
is a different type, even though its contents match up exactly.
We could do this:
func (lt *LeaveType) UnmarshalJSON(b []byte) error {
type LT LeaveType
var r LT
err := json.Unmarshal(b, &r)
if err != nil {
panic(err)
}
// ...
}
This would fill in r
, which has the same size and shape as any LeaveType
variable. Then we could use the filled-in r
to set *lt
:
*lt = LeaveType(r) // an ordinary conversion
after which we could keep going as before, using *lt
as the value. But this means that UnmarshalJSON
had to set a temporary variable r
, which we then had to copy to its final destination. Why not, instead, set up something so that UnmarshalJSON
fills in the target variable, but using the type we chose?
That's what the syntax here is for. It's not the shortest version: as Cerise Limón noted, there is a shorter way to spell it (and that shorter spelling is generally preferred). The first set of parentheses in (*LT)(lt)
is required to bind the *
—the pointer to part—to the LT
, as *LT(lt)
has the wrong binding: it means the same thing as *(LT(lt))
which is not what we want.
这篇关于Golang中的类型转换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!