从零开始学Go之接口(三):常用内置接口
Stringers:
fmt包中定义的Stringer是最普遍的接口之一。
type Stringer interface { String() string }
Stringer
是一个可以用字符串描述自己的类型。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) }
运行结果:
Arthur Dent (42 years)
Zaphod Beeblebrox (9001 years)
练习:https://tour.go-zh.org/methods/18
通过让 IPAddr
类型实现 fmt.Stringer
来打印点号分隔的地址。
例如,IPAddr{1, 2, 3, 4}
应当打印为 "1.2.3.4"
。
type IPAddr [4]byte // TODO: 给 IPAddr 添加一个 "String() string" 方法 func (i IPAddr) String(ipaddr [4]byte) string { return fmt.Sprintf("%v.%v.%v.%v", ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[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.String(ip)) } }
运行结果:
loopback: 127.0.0.1
googleDNS: 8.8.8.8
错误:
Go 程序使用 error
值来表示错误状态。
与 fmt.Stringer
类似,error
类型是一个内建接口:
type error interface { Error() string }
(与 fmt.Stringer
类似,fmt
包在打印值时也会满足 error
。)
通常函数会返回一个 error
值,调用的它的代码应当判断这个错误是否等于 nil
来进行错误处理。
i, err := strconv.Atoi("42") if err != nil { fmt.Printf("couldn't convert number: %v\n", err) return } fmt.Println("Converted integer:", i)
error
为 nil 时表示成功;非 nil 的 error
表示失败。
练习:https://tour.go-zh.org/methods/20
从之前的练习中复制 Sqrt
函数,修改它使其返回 error
值。
Sqrt
接受到一个负数时,应当返回一个非 nil 的错误值。复数同样也不被支持。
创建一个新的类型
type ErrNegativeSqrt float64
并为其实现
func (e ErrNegativeSqrt) Error() string
方法使其拥有 error
值,通过 ErrNegativeSqrt(-2).Error()
调用该方法应返回 "cannot Sqrt negative number: -2"
。
修改 Sqrt
函数,使其接受一个负数时,返回 ErrNegativeSqrt
值。
type ErrNegativeSqrt float64 func Sqrt(x float64) (float64,error) { if x>=0 { return x,nil } return 0,ErrNegativeSqrt(x) } func (e ErrNegativeSqrt) Error() string { return fmt.Sprintf("cannot Sqrt negative number: %v", float64(e))//这里要加入float64() } func main() { fmt.Println(Sqrt(2)) fmt.Println(Sqrt(-2)) }
运行结果:
2 <nil>
0 cannot Sqrt negative number: -2
注意: 在 Error
方法内调用 fmt.Sprint(e)
会让程序陷入死循环。可以通过先转换 e
来避免这个问题:fmt.Sprint(float64(e))
。
func (e ErrNegativeSqrt) Error() string { return fmt.Sprintf("cannot Sqrt negative number: %v", e)//问题代码 }
产生这个问题的原因是因为fmt.Sprintf通过接口查询知道e是一个接口类型,所以会调用e.Error()来构成一个字符串并返回,但同时e.Error()又调用了fmt.Sprintf,所以就完成了死循环。