Golang:接口方法在哪里被调用?

huangapple go评论86阅读模式
英文:

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(),对吗?

我查看了godocfmt的源代码,但仍然无法弄清楚!

另一个例子:

如果我添加自己的接口,比如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.Formatterfmt.GoStringererror,最后是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?

huangapple
  • 本文由 发表于 2015年12月12日 01:57:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/34229699.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定