英文:
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?
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论