参考 Understanding Go Interface

感谢 francesc 分享

接口

我们编程中少不了对接口使用和设计,无论你是使用哪种语言或多或少都会使用到**接口**。即使你说明重来没有显示定义过或者使用过接口,我想如果你也可能隐式地用到过接口。

今天我们就说一说 go 语言中的接口是如何设计的;如何使用的以及他与其他语言相比有什么自己的特点。

什么是 interface

接口可以理解是规范、协议、用户使用手册和对类型抽象,对行为描述。说了这么一大堆还需要您自己了解。

> In object-oriented programming, a protocal or interface is a common means for unrelated objects to communicate with each other

wikipedia

上面的话摘字 wiki,这里传递了两个重要的信息

- communicate 接口是用于通讯,接口就是用来定义通讯遵循的规则,类似一种协议。

- unrelated objects 耦合度低的对象,接口定义通讯规则可以使用两个互不相干的对象。通过接口会将关注点放在交流上,而不会关注与通讯无关的类型上。

乐高玩具就是一个好的例子。乐高玩具的一个piece 组合时只要遵守尺寸规则,无论大小和颜色就可以组合在一起进行拼接。

以后兼职工作也是一样只要满足规定的条件,在拼接 Lego 玩具时是否可以拼接是和piece 的颜色和形状没有关系的,只要他们都遵守一定尺寸就可以进行拼接。在软件控制模块搭建和通讯也是通过定义一定接口规范来实现了。我想软件工程也在某些方面借鉴传统的行业。

想到 go 我们就会自然联想到他一个项目 docker,也就是 docker 项目让我们看 go 语言的商业化,docker 可以算上是 go 的最佳实践之一了。

之所以集装箱海运如何兴旺,因为提供一个统一接口,无论是什么样船或者是列车都可以可以运输集装箱,因为集装箱提供一种标准(接口)标准的尺寸和重量。

docker 设计也是源于集装箱设计,我们将 code 进行包装,然后提供一致接口这样我们的 code 就可以运行在任何符合其标准的环境了。

### 什么是 go 的 interface

在 go 语言中我们可以通过两个维度对类型进行划分

  • - 抽象类型

  • - 实体类型

当然在 go 语言中有很多种类型,不过我们大致可以将归为两种一种类型属于 abstract 类型(抽象类型)和 concrete 类型(实体类型)

实体类型

- 用于描述类型在内存中分配情况,根据类型我们就可以知道其在内存中存在形式。

int8/int16/int32/int64/struct/float

- 使用方法赋予数据一定的行为

type Number intfunc (n Number) Positive() bool{  return n >0}

抽象类型

这种类型就是接口,并不是说明类型的形状,而是告诉你能够使用这种类型来做什么。

抽象类型并没定义描述如何为这种类型分配内存空间,而是描述类型的行为。按行为为类型进行划分。这些抽象类型有 io.Reader 、 io.Writer 和 fmt.String 等等

type Positiver interface{  Positive() bool}

在 Positiver 接口中定义了 Positive 这里大家已经注意到了我们并没有指定接口的接收者(也就是实现者)。这就是 go 语言设计初衷,也就是我不关心你是什么类型只要你有一个形状(包括函数名、参数和返回值)一致的方法,我就认为你是实现了这个接口,你属于这个类型。

用来说明 go 语言接口的经典接口 Writer 和 Reader 接口

type Reader interface{  Read(b []byte)(int,error)}type Writer interface{  Write(b []byte)(int,error)}

只要实现了接口的方法的类型就属于接口类型,所以集合是实体类型的集合。

接口的组合

type ReadWriter interface{  Read  Writer}

接口是可以组合,这个 ReadWriter 接口,当然实现这个接口类型应该是更强大而范围从图上来看却缩小了。但是接口越详细确定范围也就小。

interface{}

这里有一个 interface{} , Rob Pike 指着 interface{} 是没有任何意思,因为没有任何限制,没有限制也就是没有意义,这个应该不难理解。在 go 语言中可以用 interface 表示类型,但是从 interface{} 来看我们是无法了解其代表类型的具体信息。

使用接口原因

  • - 编写通用的算法

  • - 隐藏实现的细节

  • - 提供拦截点

以上三点是我们使用接口原因,这里逐一给大家进行讲解。

a) func writeTo(f *os.File) error

b) func writeTo(w *os.ReadWriteCloser) error

c) func writeTo(w io.Writer) error

d) func writeTo(w interface{}) error

上面选择题您选择哪个?

答案是 b 或 c,a 选项问题是这里接收一个实体类型作为参数,这样对于测试 writeTo 就造成问题,我们每次测试这个方法就需要实例化一个 File 对象,这样得不偿失。

d 答案是对参数没有任何限制,从而也就是失去意义。没有任何关于类型有价值的信息,编译器也不会进行类型检查的。

b 和 c 根据你应用场景而定,接口的方法越少,复用性就越高。

> The bigger the interface, the weaker the abstraction

rob pike

> Be conservative in what you do, be liberal in what you accept from others

这是一条 robustness 理论,这句话源于 TCP 网络协议,在 TCP 网络协议是遵循发送到网络上数据是没有问题的,而从网络上接收数据即使有问题也是可以接受的。

### 抽象数据类型

数据类型的数学模型

通过下面依据来定义数据的行为

  • - 需要考虑数据可能的值

  • - 对此类型数据的可能操作

  • - 这些操作的行为

我们看一看栈这个抽象数据模型,有什么行为

top(push(x,s)) = x

我们 push 数据 x 入栈 s 然后用 top 方法进行出栈就会得到 x,逻辑性很强吧

pop(push(x,s)) = s

我们 push 数据 x 入栈 s 然后用 pop 弹出会返回栈进行push 前的 s。

empty(new())not empty(push(s,x))

通过上面分析我们就得到数据模型 stack

top(push(x,s)) = xpop(push(x,s)) = sempty(new())!empty(push(s,x))

这个比较抽象,我们通过定义一些行为来表述一种数据结构,理解起来可能会话费一段时间,可以通过行为表述抽象数据结构,例如先进先出就是数据结构。我们用行为表述了 stack 这一抽象数据。

接下来在 go 语言中,用具体代码对上面描述进行接口定义来表述 stack 抽象数据结构。

type Stack interface{  Push(v interface{}) Stack  Pop() Stack  Empty() bool}

在抽象数据结构上我们可以定义一些算法,这里 Size 算法需要传入抽象数据结构具有 Empty() 和 Pop() 行为,而且 Size 算法并不关系实现了这两个方法的类型的详细信息。这要实现了这两个方法即可。

func Size(s Stack) int {  if s.Empty(){    return 0  }  return Size(s.Pop()) + 1}

通过定义可排序的数据结构

type Interface interface{  Less(i,j int) bool  Swap(i, j int)  Len() int}

到现在大家可能有一些了解了在 go 语言中使用接口套路,我们先根据抽象数据结构可能有的操作,来推断出这些操作的行为。在这些抽象数据结构上定义一些通用算法,这些算法接收接口作为参数,只要这些类型提供其算法所需要的行为就行。看一看我们在 Writer 和 Reader 上的一些算法。

func Fprintln(w Writer, ar ...interface{}) (int,error)func Fscan(r Reader, a ...interface{}) (int, error)func Copy(w Writer, r Reader)(int, error)

我们可以在接口上写通用方法

现在我们明白之前说的那句话了吧,我们只是提供对的,对于接收的我们只是接收就好了。

这个选择题可以帮助你判断是否对上面所讲已经理解了。

  • a) func New() *os.File

  • b) func New() io.ReadWriteCloser

  • c) func New() io.Writer

  • d) func New() interface{}

首先我们来排除 d ,因为 interface{} 是没有任何意义和帮助的。b 和 c 也没有什么区别只是限制用户使用范围,如果只想让用户有写的能力就可以用 io.Writer 。最佳答案是 a,因为 robustness 原则是我们给出应该是好的确定的所以应该是 *os.File 实体类型而非仅是限制用户的接口。

那么我们终结一下 go 语言程序 robuness 的原则吧

返回给用户(这里用户是函数调用者)应该是确定的实体类型,而接收参数应该是接口

interface接口_golang 基础(Four) 接口进阶相关推荐

  1. typescript 接口 java_Typescript基础(4)——接口

    前言 今天继续typescript的学习,开始ts接口部分的学习. 接口 接口的理解 首先,我们谈论一下现实生活中的接口.比如生活中常用的插座接口,有些插头是三孔插座的,有些是两孔插座的.插座接口规定 ...

  2. Java基础-面向接口(interface)编程

    Java基础-面向接口(interface)编程 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.接口的概念 接口是功能的集合,同样可看做是一种数据类型,是比抽象类更为抽象的&q ...

  3. Java接口的基础语法(interface)(超详细!)

    1.接口也是一种"引用数据类型".编译之后也是一个class字节码文件. 2.接口是 完全抽象 的(无法实例化).(抽象类是半抽象.)或者也可以说接口是特殊的抽象类. 3.接口怎么 ...

  4. 关于接口的基础到进阶你要知道的知识

    想了很久,闲来无事,今天想了下还是总结了下写下来,部分参考官方源码理解,还有就是这么久的理解, 如果觉得有帮助请记得点赞 先讲下接口url组成拿后台服务为例 通常一个后台请求url格式: http:/ ...

  5. 接口的基础语法和接口在开发中的作用2021-07-23java学习日记

    Javase进阶 接口的语法和接口的作用 p499-p516 关键词: 接口    implements    面向抽象编程    OCP开闭原则 接口的基础语法 1.接口也是一种引用数据类型,编译之 ...

  6. Servlet基础:接口、类、请求响应、配置、会话追踪、上下文、协作、异常

    10.1 Servlet介绍 ​ Servlet技术是Sun公司提供的一种实现动态网页的解决方案,它是基于Java编程语言的Web服务器端编程技术,主要用于在Web服务器端获得客户端的访问请求信息和动 ...

  7. TypeScript基础入门 - 接口 - 继承接口

    转载地址 TypeScript基础入门 - 接口 - 继承接口 项目实践仓库 https://github.com/durban89/typescript_demo.git tag: 1.0.13 为 ...

  8. 这样设计是否更好些~仓储接口是否应该设计成基础操作接口和扩展操作接口

    前言 我们进行linq to sql和ef时代后,底层的实现基本使用的是repository模块,即仓储模式,事实上就是把ORM实体的最基本操作进行封闭,对外层不公开操作实现的细节. 面向接口的编程 ...

  9. TypeScript基础入门 - 接口 - 可索引的类型

    转载地址 TypeScript基础入门 - 接口 - 可索引的类型 项目实践仓库 https://github.com/durban89/typescript_demo.git tag: 1.0.11 ...

最新文章

  1. 卷积神经网络如何处理一维时间序列数据?
  2. python编程试题定位列表元素的函数是_笨办法学Python 习题 34: 访问列表的元素
  3. Linux删除 指定数目行【或者所有行】删除光标到行首
  4. 超郁闷的本地连接故障解决过程!!!
  5. 基于Bind实现的DNS正反向解析及主从DNS的配置
  6. java中的构造方法,this、super的用法
  7. jquery checkbox attr区别prop
  8. Day1-dns Extension
  9. jdk1.8_googleV3免费下载(API中文文档)
  10. 知道吗?滚还是不滚的问题和信息论有关!
  11. idea菜单栏消失如何调整回来
  12. C# WinForm窗口最小化到系统托盘
  13. Linux之cp命令
  14. 【李宏毅2020 ML/DL】P99-105 Life Long Learning
  15. ICEFaces Note(7)
  16. 如何开启深度学习之旅?这三大类125篇论文为你导航(附资源下载)
  17. “微音乐”微信小程序实战开发过程
  18. multi-key map passed in for ordered parameter sort
  19. WINRAR诊断信息:不可预料的压缩文件末端
  20. 机器学习中的数学——Momentum(Gradient Descent with Momentum, GDM)

热门文章

  1. mysql的dml语句_Mysql基础入门-SQL_DML语句
  2. oracle将时间加一天,加小时,加分,加秒
  3. 聊一聊 SpringBoot 自动配置的原理
  4. mysql封装成类_python操作mysql封装成类
  5. matlab从flove,Matlab玩出新高度,变身表白女友神器_善良995的博客-CSDN博客
  6. C++实现Linux下弹出U盘的方法
  7. linux mv命令改名,linux中mv命令使用详解(移动文件或者将文件改名)
  8. linux 查看软连接_linux删除原理
  9. html显示本地磁盘 图片,手把手教你为本地磁盘增添背景图片(图解)
  10. 编辑器插件不生效在html中,关于6.04版本HTML编辑器插件使用问题!