interface
概念
- go中的接口使用隐式实现的
- LSP里式替换-一个类型可以自由的使用另一个满足相同接口的类型来进行替换
- 接口类型具体描述了一系列方法的集合,一个实现了这些方法的具体类型时这个接口类型的实例
go标准库存在大量的单方法接口的命名习惯
12345678package iotype Reader interface {Read(p []byte) (n int, err error)}type Closer interface {Close() error}接口内嵌,关注的是内嵌的方法,和组合的设计模式思想类似
12345type ReadWriterCloser interface {ReaderWriterCloser}一个类型持有一个方法,对于一个具体类型T,其一些方法的接收者可以是T也可以是T的指针,是因为比那一起隐式的获取了变量的地址。但是实际上T类型的值是不拥有所有*T指针的方法,这样就可能其实现更少的接口
IntSet类型的String方法的接收者是一个指针类型,则不能在一个不能寻址的IntSet值上调用这个方法
123type IntSet struct {/* ... */}func (*IntSet) String() stringvar _ = IntSet{}.String() // compile error : String requires *IntSet receiver但是可以在一个IntSet值上调用这个方法
12var s IntSetvar _ = s.String() // ok同时只有IntSet类型有String类型,也只有IntSet类型实现了fmt.Stringer接口
接口类型封装和隐藏了具体类型和它的值,及时具体类型有其他方法也只有接口类型暴露出来的方法会被调用,也就是说一个具体的类型可以实现很多的接口,在调用的时候看持有这个变量的类型时哪个接口,就可以调用该接口的方法,而其他接口在该类型中实现的方法是被隐藏的。
空接口interface{}可以承接任意的值
每一个具体类型的组基于他们相同的行为可以表示成一个接口类型,不需要修改具体类型的定义,这个地方感觉还是组合的思想
12345678910111213141516171819202122232425// 出售数字文化产品如音乐,书籍,电影等type Artifact interface {Title() stringCreator() []stringCreated() time.Time}type Text interface {Pages() intWords() intPageSize() int}type Audio interface {Stream() (io.Readerclose, error)RunningTime() time.DurationFormat() string}type Video interface {Stream() (io.ReadCloser, error)RunningTime() time.DurationFormat() stringResolution() (x, y int)}
flag.Value接口
flag.Duration方法
- flag可以为程序预设命令行参数,会有一个参数缺省默认值
- flag.Duration函数创建一个time.Duration类型的标记变量并且允许用户通过多种用户友好的方式来设置这个值的大小
|
|
- 首先看flag.Duration方法,返回的是一个地址指着
|
|
- 然后看CommandLine的结构体和其Duration方法
|
|
- 实际上所有的Flag值保存在FlagSet结构体中的formal(map[string] *Flag)中
|
|
flag.Parse()方法
- 首先看Parse()方法的实现
|
|
接口值
- 接口值指一个具体的类型和那个类型的值,也称为接口的动态类型和动态值
- go中提供类型信息的值实际上是类型描述符,类型时编译期的概念
- 接口的零值指的是期类型和值的部分都是nil
- 不包含任何值的nil接口和一个刚好包含nil指针的接口值是不同的
go中排序算法的实现
sort接口
|
|
go中排序函数的实现
|
|
总结
- interface是一种类型
- interfacde{}是空接口,和Java中Object类似,所有的结构体都实现了空接口
- 如果一个类型实现了一个interface的所有方法,则该类型实现了该接口
- interface变量存储的是实现结构体的值,并且只会暴露接口公开的值和方法
- 判断interface存储的类型可以使用断言来实现。value, ok := interfaceObject.(assertType)
interface的接收者是类型值还是指针在定义的时候没有严格规定,但是go语言实际上是只支持值传递。golang的语法糖会将函数里调用的指针进行隐式的转换成值,但是反过来是不行的。函数调用优先使用指针就OK了。
123456789101112131415161718192021222324252627type I interface {Get() intSet(int)}type SS struct {Age int}func (s SS) Get() int {return s.Age}func (s SS) Set(age int) {s.Age = age}func f(i I) {i.Set(10)fmt.Println(i.Get())}func main() {ss := SS{}f(&ss) //指针参数,无论函数的接收者是值还是指针都不会保存f(ss) //值参数,函数的接收者是值不会报错,是指针会编译报错}