Go语言圣经-第七章-接口
动态类型与动态值
动态类型是接口值里的具体类型信息,动态值是具体类型的值
接口值的比较
当且仅当两个接口都是nil,或者他们的动态类型相同并且动态值也根据这个动态类型的==操作符相等。
因为接口值是可以比较的,所以它可以作为map键或做为switch语句的操作数
如果两个接口值动态类型相同,但是这个动态类型是不可比较的(Slice)那么就会比较失败并panic
一个包含nil指针的接口不等于nil接口
- 包含nil指针的接口,里面的nil指针有具体的类型,只是值是nil,所以这个接口实际不是nil,而nil接口里面什么都没有
类型断言
x.(T):判断这个变量x是不是T类型
-
断言的是具体类型(int, string …)
如果成功,可以调用这个具体类型的所有方法和属性
失败会panic1
2
3
4
5var w io.Writer
w = os.Stdout
f := w.(*os.File)//断言成功,里面确实是*os.File类型,可以调用Close(), Name()等io.Writer接口没有的方法
c := w.(*bytes.Buffer)//失败,不是Buffer -
断言的是接口类型
T不是具体的类型,而是另一个接口,比如io.ReadWriter
检查x里面的东西是不是实现了T这个接口
成功,动态类型和动态值没变,能调用的方法变了,失败panic
本来有一个Writer类型的w,里面是一个File对象,只能调用Write()方法,现在做类型断言rw := w.(io.ReadWriter),现在里面的东西能Write,我猜测它可以Read(实现ReadWriter)
检查File对象确实有Read()方法,返回一个新变量,rw里面还是那个File对象,动态值没变,但是类型变为了io.ReadWriter
类型断言询问行为
- web服务器需要向网络连接(w, io.Writer)写入字符串,但是io.Writer接口只定义了Write([]byte)方法,为了适配接口,要将字符串强转为[]byte,这会在内存中分配一段新的空间并进行数据拷贝,虽然用后就丢掉,但是在服务器中,频繁的分配会影响性能
虽然w的表面类型是io.Writer,但是底层的具体对象往往有强大的功能,比如net/http的网络连接,*os.File, *bytes.Buffer, 这些类型都有一个WriteString(s string)的方法,能直接把字符串写到底层, 不用转换为[]byte
不能保证所有的io.Writer都有WriteString, 需要一种试探的方法:在函数内定义一个临时接口stringWriter, 里面包含WriteString方法, w.(stringWriter)成功,说明底层对象实现了WriteString,直接调用此方法避免内存分配,如果失败,就老老实实的转[]byte再调用Write
Go标准库直接提供了io.WriterString(w, s)函数,所以不需要写上面的判断逻辑,它会自动帮你做这种优化
fmt.Fprintf也是这么做的,当fmt需要打印一个x时, 也会进行‘试探’,
-
试探 x.(error):你有 Error() 方法吗?如果有,我就把它当错误打印。
-
试探 x.(Stringer):你有 String() 方法吗?如果有,我就调用它获取字符串来打印。
-
兜底:都没有?那我用反射(Reflection)去分析你的结构打印出来




