英文:
Golang: Where is an Interface method called?
问题
我不理解接口方法在哪个时刻被调用。我正在查看来自Go Tour的以下示例:
package main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a, z)
}
问题:
我理解func (p Person)
接收String()
方法,并返回我想要显示的string
。但是main()
方法中的fmt.Println
在某个时刻必须调用String()
,对吗?
我查看了godoc中fmt
的源代码,但仍然无法弄清楚!
另一个例子:
如果我添加自己的接口,比如Stringer2
,其中包含一个名为String2()
的方法,然后创建一个func (p Person) String2() {....}
。为什么fmt.Println
会执行String()
,但不执行String2()
?
英文:
I don't understand at which point an Interface method is being called. I'm looking at the following example from the Go Tour:
package main
import "fmt"
type Person struct {
Name string
Age int
}
func (p Person) String() string {
return fmt.Sprintf("%v (%v years)", p.Name, p.Age)
}
func main() {
a := Person{"Arthur Dent", 42}
z := Person{"Zaphod Beeblebrox", 9001}
fmt.Println(a, z)
}
Problem:
I understand that the func (p Person)
receives the String()
method and that it returns the string
I want to display. But the fmt.Println
in the main()
method has to call String()
at some point, right?
I had a look at the source of fmt
in godoc, but I still cannot figure it out!
Another example:
If I add my own interface, lets say Stringer2
with a method called String2()
and then create a func (p Person) String2() {....}
.
How does String()
get executed by fmt.Println
, but String2()
not?
答案1
得分: 12
该值作为interface{}
传递给Println
,然后通过一种称为“类型断言”的方式检查它是否满足fmt.Stringer
接口,通常以“类型开关”的形式进行检查。
func IsStringer(i interface{}) {
switch s := i.(type) {
case fmt.Stringer:
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
default:
fmt.Println("not a stringer")
}
// 或者对于单个类型
if s, ok := i.(fmt.Stringer); ok {
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
}
}
然而,在使用fmt
包进行打印时,其他方法可能具有优先权。首先检查fmt.Formatter
,fmt.GoStringer
,error
,最后是fmt.Stringer
。
英文:
The value is passed to Println
as an interface{}
, and is checked if it satisfies the fmt.Stringer
interface via a "type assertion" often in the form of a "type switch".
func IsStringer(i interface{}) {
switch s := i.(type) {
case fmt.Stringer:
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
default:
fmt.Println("not a stringer")
}
// OR for a single type
if s, ok := i.(fmt.Stringer); ok {
fmt.Println("Person a has a String() method")
fmt.Println(s.String())
}
}
However, other methods may take precedence when printing from the fmt
package. There are first checks for fmt.Formatter
, fmt.GoStringer
, error
, and then finally fmt.Stringer
.
答案2
得分: 1
fmt
包与它定义的接口一起工作,例如Stringer
接口。它不知道你定义的接口,所以即使你传递给它满足Stringer2
接口的类型,它也不会知道调用String2()
。
接口是在类型之间实现共同行为的一种方式。因此,如果你创建一个函数Foo(s Stringer2)
,Foo可以简单地调用s.String2()
,并确信任何传递给它的参数都将具有String2()
函数。
更深入地说,fmt.Println
接受interface{}
类型,然后使用反射来检查给定的参数是否满足Stringer
接口,然后调用String()
。
明白了吗?
英文:
The fmt
package works with the interfaces it defines, in this case Stringer
. It does not know of interfaces defined by you so it wouldn't know to call String2()
even if you pass it a type that meets the Stringer2
interface.
Interfaces are a way to have common behavior between types. So if you create a function Foo(s Stringer2)
, Foo can simply call s.String2()
confident that anything passed into it will have the function String2()
.
To go a bit deeper, fmt.Println
takes interface{}
types and then uses reflection to check if the given argument meets the Stringer
interface to then call String()
.
Make sense?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论