Golang笔记 4.2 go 接口

2020-04-17 18:10:31 浏览数 (1)

1 它是什么

说背景和地位

摘录自《go语言编程》

代码语言:javascript复制
接口在Go语言有着至关重要的地位。如果说goroutine和channel 是支撑起Go语言的并发模型的基石,让Go语言在如今集群化与多核化的时代成为一道极为亮丽的风景,那么接口是Go语言整个类型系统的基石,让Go语言在基础编程哲学的探索上达到前所未有的高度。

Go语言在编程哲学上是变革派,而不是改良派。这不是因为Go语言有goroutine和channel,而更重要的是因为Go语言的类型系统,更是因为Go语言的接口。 Go语言的编程哲学因为有接口而趋近完美。

Go语言的非侵入式接口,看似只是做了很小的文法调整,实则影响深远。

侵入式接口,“侵入式”的主要表现在于实现类需要明确声明自己实现了某个接口。

一句话说明

接口提供了一种方式来说明对象的行为:如果谁能搞定这件事,它就可以用在这儿。

接口定义了一组方法(方法集),但是这些方法不包含(实现)代码:它们没有被实现(它们是抽象的)。

所以一句话来说,接口是使用方法的抽象。

2 为什么需要它

接口是使用方法的抽象,使当前程序可以更聚焦在方法的应用,不关心该方法的具体实现。

3 怎么用

接口赋值

接口定义:

代码语言:javascript复制
type Integer int
func (a Integer) Less(b Integer) bool {
	return a < b
}
func (a *Integer) Add(b Integer) {
	*a  = b
}

type LessAdder interface {
	Less(b Integer) bool
	Add(b Integer)
}

接口赋值,将实例赋值给接口:

代码语言:javascript复制
var a Integer = 1
var b LessAdder = &a

接口查询

代码语言:javascript复制
var file1 Writer = ...
if file5, ok := file1.(two.IStream); ok {
	...
}

Writer接口的实现实例file1,是否实现了 two.IStream 接口,如果实现了则执行代码。

类型查询

在 Go 语言中,还可以更加直截了当地询问接口指向的对象实例的类型。

利用反射也可以进行类型查询,详情可参阅reflect.TypeOf()方法。

代码语言:javascript复制
var v1 interface{} = ...
switch v := v1.(type) {
	case int: // 现在v的类型是int
	case string: // 现在v的类型是string
	...
}

接口组合

代码语言:javascript复制
type ReadWriter interface {
	Reader
	Writer
}

这个接口组合了Reader和Writer两个接口,它完全等同于如下写法:

代码语言:javascript复制
type ReadWriter interface {
	Read(p []byte) (n int, err error)
	Write(p []byte) (n int, err error)
}

4 示例

典型示例 关注使用,不操心接口实现。来自于《GO示例学》。

// 这里定义了一个最基本的表示几何形状的方法的接口

代码语言:javascript复制
type geometry interface {
  area() float64
  perim() float64
}

// 这里不管正方形或者长方形怎么去实现自己的接口,但最后使用部分,直接用接口方法就好了。

代码语言:javascript复制
func measure(g geometry) {
  fmt.Println(g)
  fmt.Println(g.area())
  fmt.Println(g.perim())
}

5 空接口 Any类型

由于Go语言中任何对象实例都满足空接口interface{},所以interface{}看起来像是可以指向任何对象的 Any 类型,如下:

代码语言:javascript复制
var v1 interface{} = 1 // 将int类型赋值给interface{}
var v2 interface{} = "abc" // 将string类型赋值给interface{}
var v3 interface{} = &v2 // 将*interface{}类型赋值给interface{}
var v4 interface{} = struct{ X int }{1}
var v5 interface{} = &struct{ X int }{1}

当函数可以接受任意的对象实例时,我们会将其声明为interface{},最典型的例子是标准库 fmt 中 PrintXXX 系列的函数,例如:

传入参数是 可变数量的 任意类型。

代码语言:javascript复制
func Printf(fmt string, args ...interface{})
func Println(args ...interface{})

总体来说, 我们刚开始对 interface{} 一无所知,但可以通过接口查询和类型查询逐步了解它。

6 小结

总结,接口是使用方法的抽象,使当前程序可以更聚焦在方法的应用,不关心该方法的具体实现。后续的应用程序在做具体实现时,再去完善具体实现,不会影响之前程序已经定义好的逻辑。

更通俗地来讲,接口的定义,就像是设置了一个岗位,描述了岗位的职责;,一些规章可以先根据岗位职责来制定,不关心具体是谁来任职这个岗位。当应用程序开始执行的时候,需要给接口传入一个实例,相当于企业开始运营时再把一个人放到这个岗位。

另外空接口 interface{} 作为 Any 类型也有很广到应用。

END

0 人点赞