这一章继续探索接口 interface。
有的时候,我们需要根据接口 interface 的值类型来做不同的处理,这就需要有判断的能力。
go 提供了“类型断言”(type assertion)的写法:
t, ok := i.(T)
来看下官方给的例子:
package main
import "fmt"
func main() {
var i interface{} = "hello" // 定义一个空接口,赋值字符串 “hello”
s := i.(string) // 类型断言为字符串 string 类型
fmt.Println(s)
s, ok := i.(string) // 加入ok变量,获得类型断言结果
fmt.Println(s, ok)
f, ok := i.(float64) // 类型断言失败,会返回空值以及 false
fmt.Println(f, ok)
f = i.(float64) // panic // 不适用ok变量,类型断言失败会直接报错
fmt.Println(f)
}
接口 interface 类型断言也可以用 switch 关键字,正好也展示一下类型断言的实际代码演示:
package main
import "fmt"
func do(i interface{}) {
switch v := i.(type) { // switch 关键词进行类型断言
case int:
fmt.Printf("Twice %v is %v\n", v, v*2)
case string:
fmt.Printf("%q is %v bytes long\n", v, len(v))
default:
fmt.Printf("I don't know about type %T!\n", v)
}
}
func main() {
do(21)
do("hello")
do(true)
}
我们已经学习了很多关于接口 interface 的知识,来看看具体怎么应用。
先来看看 go 源代码是怎么使用接口的,在 fmt 这个官方实现包里,定义了 Stringer 接口:
type Stringer interface {
String() string
}
Stringer 接口定义了 String 方法,在使用 fmt 包进行打印的时候,实际上就是调用 String 方法。
通过自定义实现 String 方法,可以实现想要的打印结果:
package main
import "fmt"
type Person struct { // 定义 Person 结构体
Name string
Age int
}
func (p Person) String() 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) // 调用 fmt 打印,实际上就是调用上面自定义的 String 方法
}
知道了 Stringer 接口,我们来实现一个打印 IP 地址的功能:
package main
import "fmt"
type IPAddr [4]byte
func (ip IPAddr) String() string { // 打印 IP 地址
return fmt.Sprintf("%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[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)
}
}
ok,这一章结束,我们就讲完了接口 interface。