我尝试Stringer在我的类型上实现接口如下:
package main
import (
"fmt"
)
type IPAddr [4]byte
// TODO: Add a "String() string" method to IPAddr.
func (o IPAddr) String() string {
return fmt.Sprintf("%v.%v.%v.%v", o[0], o[1], o[2], o[3])
}
func main() {
hosts := map[string]IPAddr{
"loopback": {127, 0, 0, 1},
"googleDNS": {8, 8, 8, 8},
}
for name, ip := range hosts {
fmt.Printf("%v: %v\n", name, ip)
fmt.Printf("%v\n", ip.String())
}
}
Run Code Online (Sandbox Code Playgroud)
在上面的代码中,我使用了一个值接收器来实现该String()方法。在Printf承认我的实现,并呼吁正确的String我型功能。
输出:
googleDNS: 8.8.8.8
8.8.8.8
loopback: 127.0.0.1
127.0.0.1
Run Code Online (Sandbox Code Playgroud)
然后我更新了我的代码以使用指针接收器:
func (o *IPAddr) String() string {
return fmt.Sprintf("%v.%v.%v.%v", o[0], o[1], o[2], o[3])
}
Run Code Online (Sandbox Code Playgroud)
更新代码的输出:
loopback: [127 0 0 1]
127.0.0.1
googleDNS: [8 8 8 8]
8.8.8.8
Run Code Online (Sandbox Code Playgroud)
该Printf方法不再调用我的String方法。输出告诉我Printf使用String该类型的默认方法。但是,当我调用 时ip.String(),使用了我的方法。
有人可以向我解释这种行为吗?据我所知,我们可以通过值和指针接收器来实现接口的方法。
谢谢你。
小智 6
该%v转换指定将读取任何满足方法Stringer接口。但是,要发生这种情况,该方法必须存在于值的方法集中。
对于 type 值T,其方法集包含任何接收该类型值的方法T:
func (t T) Foo() // in the method set of T
func (t *T) Bar() // not in the method set of T
Run Code Online (Sandbox Code Playgroud)
对于 type 指针*T,其方法集包含接收 type 值的方法和 typeT指针*T:
func (t T) Foo() // in the method set of *T
func (t *T) Bar() // in the method set of *T
Run Code Online (Sandbox Code Playgroud)
在 中main,您有一个标识为iptype的值IPAddr,因此上面的第一组注释代码适用。
您的第一个示例将起作用,因为该方法的方法接收器String具有 type IPAddr。
在第二个示例中,方法的方法接收者String具有 type *IPAddr,这意味着它不在ip具有 type的方法集中IPAddr。
总之:
| String() Method | fmt.Print, fmt.Printf, etc.
Input Type | Receiver | calls String() implicitly
========== | =============== | ===========================
*IPAddr | IPAddr | Yes
| *IPAddr | Yes
---------- + --------------- + ---------------------------
IPAddr | IPAddr | Yes
| *IPAddr | No
Run Code Online (Sandbox Code Playgroud)
您可能想知道为什么会发生这种情况。事实证明,某些值可能无法寻址,因此具有类型的方法接收器*IPAddr无法接收没有地址的值。例如,尝试IPAddr{}.String()使用*IPAddr方法接收器执行。它将无法编译,因为文字值没有地址。如果你改为使用(&IPAddr{}).String(),它会起作用,因为现在你有一个*IPAddr使用创建的指针&IPAddr{},如果你使用非指针接收器IPAddr,那么无论 是否IPAddr可寻址,它都会起作用。