英文:
convert function type in Golang
问题
// 每个类型都有一个 Error() string 方法。
// error 内置接口类型是表示错误条件的常规接口,nil 值表示没有错误。
// type error interface {
// Error() string
// }
func (f binFunc) Error() string {
return "binFunc error"
}
func func_type_convert() {
var err error
err = binFunc(add)
fmt.Println(err)
fmt.Println(i)
}
关于上面的代码,我有两个问题:
- 当将
add
函数转换为binFunc
类型时,我不知道为什么会执行Error
方法? - 为什么能将
add
函数转换的结果赋值给一个err
error 接口变量?
英文:
// Each type have Error() string method.
// The error built-in interface type is the conventional interface for
// representing an error condition, with the nil value representing no error.
// type error interface {
// Error() string
// }
func (f binFunc) Error() string {
return "binFunc error"
}
func func_type_convert() {
var err error
err = binFunc(add)
fmt.Println(err)
fmt.Println(i)
}
I have two questions about the code above:
- I don't know why the
Error
method executed, whenadd
function was converted intobinFunc
type? - Why the
add
function converted result was able to assign to an err error interface variable?
答案1
得分: 12
error
是一个接口:
type error interface {
Error() string
}
这意味着任何具有Error() string
方法的类型都满足该接口,并且可以赋值给error
类型的变量。
binFunc
具有这样的方法:
func (f binFunc) Error() string {
return "binFunc error"
}
Go中的新开发人员有时会觉得这很困惑,因为他们没有意识到可以将方法附加到除结构体以外的其他类型。在这种情况下,binFunc
的定义如下:
type binFunc func(int, int) int
因此,这样的工作方式是允许您将具有相同签名的任何函数进行转换(来自规范):
函数类型表示具有相同参数和结果类型的所有函数的集合。
因此,如果您创建一个函数add
:
func add(x, y int) int {
return x + y
}
您可以将其转换为binFunc
:
binFunc(add)
由于我们在上面定义的binFunc
具有Error
方法,因此我们可以将这个新的binFunc
赋值给error
类型的变量:
var err error
var bf binFunc = binFunc(add)
err = bf
fmt.Println
的行为是在错误上调用.Error()
来打印:
- 如果操作数实现了错误接口,则将调用Error方法将对象转换为字符串,然后根据所需的动词进行格式化。
所以回答你的问题:
-
执行
Error
方法是因为fmt.Println
寻找error
类型的参数,调用.Error()
并打印结果字符串。 -
您可以将
binFunc
赋值给err
,因为binFunc
具有Error
方法。您不能直接将add
赋值给err
,因为它没有Error
方法。但是,您可以将add
转换为binFunc
,因为它们具有相同的函数签名,通过这样做,您可以将其赋值给err
变量。
英文:
error
is an interface:
type error interface {
Error() string
}
This means that any type which has a method: Error() string
fulfills the interface and can be assigned to a variable of type error
.
binFunc
has such a method:
func (f binFunc) Error() string {
return "binFunc error"
}
New developers in Go sometimes find this confusing because they don't realize it's possible to attach methods to more than just structs. In this case binFunc
is defined liked this:
type binFunc func(int, int) int
So the way this works is you are allowed to convert any function which has the same signature: (from the spec)
> A function type denotes the set of all functions with the same parameter and result types.
So if you create a function add
:
func add(x, y int) int {
return x + y
}
You are allowed to convert this into a binFunc
:
binFunc(add)
And because of the Error
method on binFunc
we defined above, we are then able to assign this new binFunc
to a variable of type error
:
var err error
var bf binFunc = binFunc(add)
err = bf
fmt.Println
's behavior is to call .Error()
on errors for you:
> 4. If an operand implements the error interface, the Error method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any).
So to answer your questions:
-
The
Error
method is executed becausefmt.Println
looks for arguments of typeerror
, invokes.Error()
and prints the resulting string. -
You are allowed to assign
binFunc
s toerr
becausebinFunc
has anError
method. You cannot assignadd
directly toerr
because it does not have anError
method. But you are allowed to convertadd
to abinFunc
because they have the same function signature, and by doing so you can then assign it to theerr
variable.
答案2
得分: 0
go规范中的依赖关系:
类型转换或转换 -> 可赋值性 -> 类型标识
- 显式类型转换或转换
binFunc
和 func(int, int) int
具有相同的底层表示。
binFunc(add)
注意,类型转换可以发生在具有相同底层表示的两种类型之间。然而,它们的类型可以完全不同。
type MyInt int
func main() {
var b MyInt = 3
a := int(b)
fmt.Println(a, b)
}
- 变量赋值
查看类型标识
根据类型标识规则,binFunc
与 func(int, int) int
是相同的。因此,您可以进行如下的类型转换:
如果命名类型与任何其他类型都不同。否则,如果它们的底层类型文字在结构上等效,则两个类型是相同的;也就是说,它们具有相同的文字结构,并且相应的组件具有相同的类型。
func(int, int) int
是类型文字,它是无名的。
type binFunc func(int, int) int
是一个命名类型。
预声明类型、定义类型和类型参数被称为命名类型。如果别名声明中给出的类型是命名类型,则别名表示命名类型。
命名类型与其他类型不同。但在这里,binFunc
与无名类型进行比较:它们的底层类型文字在结构上等效,都是 func(int, int) int
。
var bfunc binFunc = add
查看可赋值性
命名类型的变量可以赋值为无名类型的值,前提是它们的底层类型是相同的。
在这里,可以称之为隐式类型转换,但这并不准确。至少在Go语言中,不称之为类型转换,因为底层类型/表示是相同的。
受此答案的启发
额外的说明
类型断言只需要类型标识。因此,规则比可赋值性更简单。
英文:
go spec dependencies:
type casting or conversion -> assignability -> type identity
- explicit type casting or conversion
binFunc
and func(int, int) int
have same underlying representation.
binFunc(add)
note, type casting can happen between 2 types that have the same underlying representation. However, their type can be totally different.
type MyInt int
func main() {
var b MyInt = 3
a := int(b)
fmt.Println(a, b)
}
- variable assignment
check type identity
based on type identity rule, binFunc
is identical to func(int, int) int
. So you can do type casting as below:
> A named type is always different from any other type. Otherwise, two types are identical if their underlying type literals are structurally equivalent; that is, they have the same literal structure and corresponding components have identical types.
func(int, int) int
is type literal, and it's unnamed.
type binFunc func(int, int) int
is a named type.
> Predeclared types, defined types, and type parameters are called named types. An alias denotes a named type if the type given in the alias declaration is a named type.
named type is different from others. but here, binFunc
is compared with the un-named type: their underlying type literals are structurally equivalent, both func(int, int) int
.
var bfunc binFunc = add
check assignability
variable of named type can be assigned with a value of unnamed type providing their underlying type is identical.
You may call this an implicit type conversion here, but it's not accurate. At least golang doesn't call this type conversion because the underlying type/representation is the same.
inspired by this answer
extra words
type assertion only requires type identity. Therefore, the rule is simpler than type assignability.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论