从零开始学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,所以就完成了死循环。

 

posted @ 2019-07-02 12:33  VingB2by  阅读(486)  评论(0编辑  收藏  举报