1. 什么是interface
在此之前,我们遇到的都是具体的类型,比如数字类型、切片类型等等。对于这些具体的类型,我们总是能知道它是什么、可以利用它来做什么,比如对于一个数字类型,我们知道可以对其进行算数操作;对于一个切片类型,我们知道可以取下标操作等等。但是,接口类型是一种抽象的类型,我们并不能知道接口内存放的对象的值是什么,也不知道这个对象支持哪些操作。唯一知道的就是可以利用接口提供的方法来做一些事情。

简单的说,interface是一组method的组合,我们通过interface来定义对象的一组行为。我们称一个实现了这些方法的具体类型为这个接口类型的实例

首先,来看一个简单的例子。

下面的语句定义了一个简单的接口:
type geometry interface {
area() float64
perimeter() float64
}

然后定义一个结构体 circle:
type circle struct{
radius float64
}

接着,对 circle 类型实现 geometry 接口。我们说一个类型实现了某个接口,就是说这个类型实现了该接口中定义的所有方法。
func (c circle) area() float64 {
return math.Pi * c.radius * c.radius
}

func (c circle) perimeter() float64 {
return 2 * math.Pi * c.radius
}

我们再定义一个显示方法show(),如下:
func show(g geometry) {
fmt.Println(g)
fmt.Println(g.area())
fmt.Println(g.perimeter())
}

最后,在 main() 方法中初始化一个 circle 对象,并执行相应函数。
func main() {
c := circle{radius:3} // 初始化一个 circle 对象
show(c)
}

表达一个类型属于某个接口,只要这个类型实现了这个接口。所以,下面语句是合理的:
var g geometry
c := circle{radius:3}
g = c // ok,因为 circle 类型实现了 geometry 接口内声明的所有方法。因此可以说 circle 属于 geometry

但是,假设现在有一个类型是 rect,但是它只实现了 geometry 接口中的 area() 方法,如下:
type rect struct {
width, height float64
}
func (r rect) area() float64 {
return r.height * r.width
}

那么此时,执行如下语句就是错误的:
r := rect{width:10, height:5}
g = r // compile error, rect type lacks perimeter() method

此外,一个对象还可以实现任意多个interface,例如,现在再定义一个Foo 接口(这里只是为了示例,并无意义),如下:
type Foo interface {
foo()
}

那么,circle 对象还可以实现该接口。同样的,只要 circle 类型实现了 Foo 接口内定义的所有方法,我们就说 circle 也属于 Foo
type Foo interface {
sayHi(s string)
}

func (c circle) sayHi(s string) {
fmt.Println("Hi, I am ", s)
}

// 以下是成立的
var f Foo
f = c
f.sayHi("circle")

总结:一个 interface 可以被任意个不同类型的对象实现(比如,geometry 接口可以被 circle、rect 等对象实现);一个对象也可以实现任意个 interface(比如,circle 类型就实现了 geometry 和 Foo 这两个接口 )。最关键的是,我们说一个类型实现了某个接口,指的是这个类型实现了该接口中定义的所有方法。一旦一个类型实现了某个接口,我们就说这个类型属于该接口,从而可以把这个类型的值赋给其接口类型的值。

最后,任意的类型都实现了空interface(写为:interface{}),也就是包含 0 个method 的interface。

2. interface 值
如果我们定义了一个 interface 的变量,那么这个变量到底可以存放什么值呢?其实这个问题的答案在第1部分的例子中已经回答了,在上面的例子中,我们定义了一个 geometry 接口的变量(var g geometry),可以把 circle 类型的变量 c 赋值给 g——因为 circle 类型实现了 geometry 接口。当然,如果还有别的类型,比如 rect、triangle...只要它们实现了 geometry 接口,那么变量 g 就都可以“接受”它们。总的来说,如果我们定义了一个 interface 的变量,那么这个变量里面就可以存实现了这个 interface 的任意类型的对象。

3. 空 interface(interface{})
空 interface不包含任何的 method,正因为如此,可以认为所有的类型都实现了 interface{}。空interface对于描述起不到任何的作用(因为它不包含任何的method),但是空interface在我们需要存储任意类型的数值的时候相当有用,因为它可以存储任意类型的数值。它有点类似于C语言的 void* 类型。一个函数把interface{}作为参数,那么他可以接受任意类型的值作为参数,如果一个函数返回interface{},那么也就可以返回任意类型的值。
示例代码:
var v interface{} // v定义为空接口
var i int = 23
var s string = "hello, zju"
// v 可以存储任意类型的值
v = i // ok
v = s // ok

参考
关于interface的一篇还不错的文章
https://www.jb51.net/article/56812.htm

Go之接口interface(1)的更多相关文章

  1. java中的接口interface

    关于接口 接口描述了实现了它的类拥有什么功能.因为Java是强类型的,所以有些操作必须用接口去约束和标记.接口作为类的能力的证明,它表明了实现了接口的类能做什么. 类似与class,interface ...

  2. php中的抽象类(abstract class)和接口(interface)

    一. 抽象类abstract class 1 .抽象类是指在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类. 2 ...

  3. 14 接口-interface的定义与实现

    接口的基本语法一: 1.使用interface 定义 2.接口当中的方法都是抽象方法 3.接口当中的方法都是public权限 接口的定义: interface USB { public void re ...

  4. C#编程利器之三:接口(Interface)【转】

    C#编程利器之三:接口(Interface) C#接口是一个让很多初学者容易迷糊的东西,用起来好象很简单,定义接口,然后在里面定义方法,通过继承与他的子类来完成具体的实现.但没有真正认识接口的作用的时 ...

  5. 为什么不能把委托(delegate)放在一个接口(interface)当中?

    stackoverflow上有人问,为什么不能把委托放在一个接口当中? 投票最多的第一个答案第一句话说,“A Delegate is just another type, so you don't g ...

  6. java之接口interface

    接口 1.多个无关的类可以实现同一个接口 2.一个类可以实现多个无关的接口 3.与继承关系类似,接口与实现类之间存在多态性 4.定义java类的语法格式 < modifier> class ...

  7. 【Java 基础篇】【第六课】接口interface

    Java提供的这个interface的语法,目的就是将接口从类中剥离出来,构成独立的主体. 首先加入我们定义了这个杯子接口: interface Cup { void addWater(int w); ...

  8. TypeScript学习指南第二章--接口(Interface)

    接口(Interface) TypeScript的核心机制之一在于它的类型检查系统(type-checker)只关注一个变量的"模型(shape)" 稍后我们去了解这个所谓的形状是 ...

  9. Go语言学习笔记(四)结构体struct & 接口Interface & 反射

    加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套: go中的struc ...

  10. Java接口interface

    Java接口interface 1.多个无关的类可以实现同一个接口. 2.一个类可以实现多个无关的接口. 3.与继承关系类似,接口与实现类之间存在多态性. 接口(interface)是抽象方法和常量值 ...

随机推荐

  1. [GXOI/GZOI2019]特技飞行

    题目链接 [https://www.luogu.org/problem/P5302] 思路:这道题可以说是两道题的合并.注意到\(c\)的分数与 \(a\)和\(b\)的分数 无关,也就是说可以分成两 ...

  2. luogu P2018 消息传递

    二次联通门 : luogu P2018 消息传递 /* luogu P2018 消息传递 树形dp 原来用优先队列做了一下, T了俩点 MMP 去看正解.. 复杂度一样好不好.. 每次到达一个点,记录 ...

  3. 炸掉的fft,改天再调

    #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> ...

  4. 服务器之poll

    poll服务器方法采用将监听端口用数组存放起来,这样就不需要轮询的监听整个文件描述符了 #include <poll.h> int poll(struct pollfd *fds, nfd ...

  5. centos7 浏览器(firefox)中文乱码

    主要问题在于firefox用了系统没有的字体 百度的方案: 通过yum安装中文字体 (找不到对应的库) 修改firefox的默认字体(尴尬.不知道改哪个才有效) 粗暴的解决方案: 把 windows ...

  6. Asp.Net.Mvc+MEF+EF 项目 ,源码在GitHub ..希望对大家有所帮助

    自己开源的 一个 Asp.Net + MEF+ EF 的 项目 . 供大家学习和使用, 点击进入GitHub

  7. BZOJ3236作业

    这东西是个应用为O(logn)的莫队. 正常莫队的updata函数转移是O(1)的,可这个题时间非常宽泛,可以套两个树状数组,那两个东西很好维护,第一个直接普通权值树状数组维护,第二个开一个桶,记录当 ...

  8. Vue源码分析(一) : new Vue() 做了什么

    Vue源码分析(一) : new Vue() 做了什么 author: @TiffanysBear 在了解new Vue做了什么之前,我们先对Vue源码做一些基础的了解,如果你已经对基础的源码目录设计 ...

  9. mac电脑如何快速显示桌面及切换应用

    使用mac电脑时,我们习惯打开很多应用,文档等等.如果打开应用非常多,需要操作桌面,却不知如何快速返回桌面和切换应用时,操作就非常不便了,下面简单介绍mac电脑系统如何快速显示桌面及切换应用? 工具/ ...

  10. Macbook上打开多个终端的方法

    方法有如下两种 1.首先是的焦点在终端上(使用鼠标点击下终端).然后使用快捷键command+N 即可得到另一个终端界面. (如果现在光标的焦点在浏览器上,那么就是新打开一个浏览器窗口) 2.同样,光 ...