Go 接口(interface)
文章转载地址:https://www.flysnow.org/2017/04/03/go-in-action-go-interface.html
1.什么是 interface?
简单的说,interface 是一组 method 签名的组合,通过 interface 定义对象的一组行为
上一篇文章中我们实现了 Student 和 Employee 都能 SayHi,现在我们进一步做扩展,Student 和 Employee
实现另一个方法 Sing,然后 Student 实现方法 BorrowMoney 而 Employee 实现 SpendSalary
这样,Student 实现了三个方法:SayHi,Sing,BorrowMoney ;而 Employee 实现了 SayHi,Sing, SpendSalary
上面这些方法的组合被称为 interface(被对象 Student 和 Employee 实现)。例如:Student 和 Employee 都实现了 interface:
SayHi,Sing,也就是这两个对象是该 interface 类型。而 Employee 没有实现这个 interface:SayHi,Sing,BorrowMoney,
是因为 Employee 没有实现 BorrowMoney 这个方法
2. interface 类型
interface 定义了一组方法,如果某个对象实现了某个接口的所有方法,则此对象就实现了这个接口
package main import "fmt" // 定义 Human 结构体
type Human struct {
name string
age int
phone string
} // 定义 Student 结构体
type Student struct {
Human // 匿名字段
company string
loan float32
} // 定义结构体 Employee
type Employee struct {
Human // 匿名字段
company string
money float32
} // Human 实现 SayHi 方法
func (h *Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
} // Human 实现 Sing 方法 传入 lyrics(歌词) 参数
func (h *Human) Sing(lyrics string) {
fmt.Println("La la, la la la, la la la la la...", lyrics)
} // Human 实现 Guzzle 方法
func (h *Human) Guzzle(beerStein string) {
fmt.Println("Guzzle Guzzle Guzzle...", beerStein)
} // Employee 重载 Human 的 SayHi 方法
func (e *Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone)
} // Student 实现 BorrowMoney 方法
func (s *Student) BorrowMoney(amount float32) {
s.loan += amount
} // Employee 实现 SpendSalary 方法
func (e *Employee) SpendSalary(amount float32) {
e.money -= amount
} // 定义 interface
type Men interface {
SayHi()
Sing(lyrics string)
Guzzle(beerStein string)
} type YoungChap interface {
SayHi()
Sing(lyrics string)
BorrowMoney(amount float32)
} type ElderlyGent interface {
SayHi()
Sing(lyrics string)
SpendSalary(amount float32)
} func main() { }
通过上面的代码我们可以知道,interface 可以被任意的对象实现。我们看到上面的 Men interface 被 Human、Student、Employee
实现(一个接口可以被多个对象实现)。同理,一个对象可以实现任意多个接口,例如上面的 Student 实现了 Men 和 YoungChap 两个interface
最后,任意的类型都实现了空接口(interface{})
3. interface 值
package main import "fmt" // 定义 Human 结构体
type Human struct {
name string
age int
phone string
} // 定义 Student 结构体
type Student struct {
Human // 匿名字段
company string
loan float32
} // 定义结构体 Employee
type Employee struct {
Human // 匿名字段
company string
money float32
} // Human 实现 SayHi 方法
func (h Human) SayHi() {
fmt.Printf("Hi, I am %s you can call me on %s\n", h.name, h.phone)
} // Human 实现 Sing 方法 传入 lyrics(歌词) 参数
func (h Human) Sing(lyrics string) {
fmt.Println("La la, la la la, la la la la la...", lyrics)
} // Employee 重载 Human 的 SayHi 方法
func (e Employee) SayHi() {
fmt.Printf("Hi, I am %s, I work at %s. Call me on %s\n", e.name,
e.company, e.phone)
} // Interface Men 都被 Human、Student、Employee 实现
type Men interface {
SayHi()
Sing(lyrics string)
} func main() {
mike := Student{Human{"Mike",25,"222-222-xxx"},"MIT",0.00}
paul := Student{Human{"Paul",26,"111-222-xxx"},"Harvard",100} sam := Employee{Human{"Sam",36,"444-222-xxx"},"Golang Inc.",1000}
tom := Employee{Human{"Tom",37,"222-444-xxx"},"Things Ltd.",5000} // 定义 Men 类型的 i
var i Men // i 能存储 Student
i = mike
fmt.Println("This is Mike,a Student:")
i.SayHi()
i.Sing("November rain") // i 也能存储 Employee
i = tom
fmt.Println("This is tom, an Employee:")
i.SayHi()
i.Sing("Born to be wild") // 定义slice Men
fmt.Println("Let's use a slice of Men and see what happens")
x := make([]Men,3) // 这三个都是不同类型的元素,但是他们实现了interface同一个接口
x[0],x[1],x[2] = paul,sam,mike for _,value := range x{
value.SayHi()
}
} -------------------------------------------------------------------------- 输出结果: This is Mike,a Student:
Hi, I am Mike you can call me on 222-222-xxx
La la, la la la, la la la la la... November rain
This is tom, an Employee:
Hi, I am Tom, I work at Things Ltd.. Call me on 222-444-xxx
La la, la la la, la la la la la... Born to be wild
Let's use a slice of Men and see what happens
Hi, I am Paul you can call me on 111-222-xxx
Hi, I am Sam, I work at Golang Inc.. Call me on 444-222-xxx
Hi, I am Mike you can call me on 222-222-xxx
4.空 interface
空 interface(interface{}) 不包含任何的 method,正因为如此,所有类型都实现了空 interface。空 interface 对于描述
起不到任何作用(因为它不包含任何的 method),但是空 interface 在我们需要存储任意类型的数值的时候相当有用,因
为它可以存储任意类型的数值。如下示例:
// 定义 a 为空接口
var a interface{}
var i int = 5 s := "Hello world' // a 可以存储任意类型的数值
a = i
a = s
一个函数把 interface{} 作为参数,则可以接受任意类型的值作为参数,如果一个函数返回 interface{} ,那么也就可以
返回任意类型的值
5.interface 变量存储的类型
我们知道 interface 的变量里面可以存储任意类型的数值(该类型实现了 interface),那么我们如何反向知道这个变量里面实际保存
的是哪个类型的对象?目前有两种方式:
5.1 Comma-ok 断言
Go 语言里面有一个语法,可以直接判断是否是该类型的变量:value,ok = element.(T),这里 value 就是变量的值,ok 是一个
bool 类型,element 是 interface 变量,T 是断言的类型
如果 element 里面确实存储了 T 类型的数值,那么 ok 返回 true,否则返回 false
如下示例:
package main import (
"fmt"
"strconv"
) // 定义一个空接口
type Eelement interface {} type List [] Eelement // 定义一个 Person 结构体
type Person struct {
name string
age int
} // 给 Person 绑定一个方法
func (p Person) String() string{
return "(name: " + p.name + " - age: "+strconv.Itoa(p.age)+ " years)"
} func main() {
list := make(List,3)
list[0] = 1 // an int
list[1] = "Hello" // a string
list[2] = Person{"Dennis",70} for index,element := range list{
// 类型判断
if value,ok := element.(int);ok{
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
}else if value,ok := element.(string);ok{
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
}else if value,ok := element.(Person);ok{
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
}else{
fmt.Printf("list[%d] is of a different type\n", index)
}
}
}
---------------------------------------------------------------------------------- 输出结果: list[0] is an int and its value is 1
list[1] is a string and its value is Hello
list[2] is a Person and its value is (name: Dennis - age: 70 years)
5.2 type-switch
直接看示例:
package main import (
"fmt"
"strconv"
) // 定义一个空接口
type Eelement interface {} type List [] Eelement // 定义一个 Person 结构体
type Person struct {
name string
age int
} // 给 Person 绑定一个方法
func (p Person) String() string{
return "(name: " + p.name + " - age: "+strconv.Itoa(p.age)+ " years)"
} func main() {
list := make(List,3)
list[0] = 1 // an int
list[1] = "Hello" // a string
list[2] = Person{"Dennis",70} for index,element := range list{
// 使用 type-switch 做类型判断
switch value := element.(type) {
case int:
fmt.Printf("list[%d] is an int and its value is %d\n", index, value)
case string:
fmt.Printf("list[%d] is a string and its value is %s\n", index, value)
case Person:
fmt.Printf("list[%d] is a Person and its value is %s\n", index, value)
default:
fmt.Println("list[%d] is of a different type", index)
}
}
} ------------------------------------------------------------------------------------- 输出结果: list[0] is an int and its value is 1
list[1] is a string and its value is Hello
list[2] is a Person and its value is (name: Dennis - age: 70 years)
6. 嵌入 interface
如果一个 interface1 作为 interface2 的一个嵌入字段,那么 interface2 隐式的包含了 interface1 里面的method
在源码包 container/heap 里面有这样的一个定义:
type Interface interface {
sort.Interface
Push(x interface{}) // add x as element Len()
Pop() interface{} // remove and return element Len() - 1.
}
看如上代码片段,我们看到 sort.Interface 其实就是嵌入字段,把 sort.Interface 的所有 method 给隐式的包含进来了,
即下面的方法:
type Interface interface {
// Len is the number of elements in the collection.
Len() int
// Less reports whether the element with
// index i should sort before the element with index j.
Less(i, j int) bool
// Swap swaps the elements with indexes i and j.
Swap(i, j int)
}
另外一个就是 io 包下面的 io.ReadWriter ,它包含了 io 包下面的两个 interface:Reader、Writer
// ReadWriter is the interface that groups the basic Read and Write methods.
type ReadWriter interface {
Reader
Writer
}
下面再来看一个示例:
package main import "fmt" // 定义一个 USB interface
type USB interface {
Name() string
// interface 嵌入
Connecter
} // 定义一个 Connecter interface
type Connecter interface {
Connect()
} // 定义一个 struct
type PhoneConnecter struct {
name string
} // 给 PhoneConnecter 绑定 Name 方法
func (pc PhoneConnecter) Name() string{
return pc.name
} // 绑定 Connect 方法
func (pc PhoneConnecter) Connect() {
fmt.Println("Connected:",pc.name)
} func main() {
a := PhoneConnecter{"PhoneConnecter"}
a.Name()
a.Connect()
}
Go 接口(interface)的更多相关文章
- java中的接口interface
关于接口 接口描述了实现了它的类拥有什么功能.因为Java是强类型的,所以有些操作必须用接口去约束和标记.接口作为类的能力的证明,它表明了实现了接口的类能做什么. 类似与class,interface ...
- php中的抽象类(abstract class)和接口(interface)
一. 抽象类abstract class 1 .抽象类是指在 class 前加了 abstract 关键字且存在抽象方法(在类方法 function 关键字前加了 abstract 关键字)的类. 2 ...
- 14 接口-interface的定义与实现
接口的基本语法一: 1.使用interface 定义 2.接口当中的方法都是抽象方法 3.接口当中的方法都是public权限 接口的定义: interface USB { public void re ...
- C#编程利器之三:接口(Interface)【转】
C#编程利器之三:接口(Interface) C#接口是一个让很多初学者容易迷糊的东西,用起来好象很简单,定义接口,然后在里面定义方法,通过继承与他的子类来完成具体的实现.但没有真正认识接口的作用的时 ...
- 为什么不能把委托(delegate)放在一个接口(interface)当中?
stackoverflow上有人问,为什么不能把委托放在一个接口当中? 投票最多的第一个答案第一句话说,“A Delegate is just another type, so you don't g ...
- java之接口interface
接口 1.多个无关的类可以实现同一个接口 2.一个类可以实现多个无关的接口 3.与继承关系类似,接口与实现类之间存在多态性 4.定义java类的语法格式 < modifier> class ...
- 【Java 基础篇】【第六课】接口interface
Java提供的这个interface的语法,目的就是将接口从类中剥离出来,构成独立的主体. 首先加入我们定义了这个杯子接口: interface Cup { void addWater(int w); ...
- TypeScript学习指南第二章--接口(Interface)
接口(Interface) TypeScript的核心机制之一在于它的类型检查系统(type-checker)只关注一个变量的"模型(shape)" 稍后我们去了解这个所谓的形状是 ...
- Go语言学习笔记(四)结构体struct & 接口Interface & 反射
加 Golang学习 QQ群共同学习进步成家立业工作 ^-^ 群号:96933959 结构体struct struct 用来自定义复杂数据结构,可以包含多个字段(属性),可以嵌套: go中的struc ...
- Java接口interface
Java接口interface 1.多个无关的类可以实现同一个接口. 2.一个类可以实现多个无关的接口. 3.与继承关系类似,接口与实现类之间存在多态性. 接口(interface)是抽象方法和常量值 ...
随机推荐
- 8 Oracle语句
1.select name from v$datafile; 用sys方式登陆,查询所有表空间存放的物理路径 2.create tablespace DEMO_TBS datafile 'D:/TBS ...
- Express中间件的原理及实现
在Node开发中免不了要使用框架,比如express.koa.koa2拿使用的最多的express来举例子开发中肯定会用到很多类似于下面的这种代码 var express = require('exp ...
- hadoop伪分布环境快速搭建
1.首先下载一个完成已经进行简单配置好的镜像文件(hadoop,HBASE,eclipse,jdk环境已经搭建好,tomcat为7.0版本,建议更改为tomcat8.5版本,运行比较稳定). 2安装V ...
- servlet转发重定向
1.request.getRequestDispacther("/test.jsp").forword(request,response); 转发 浏览器URL是一个地 ...
- python下载网页视频
因网站不同需要修改. 下载 mp4 连接 from bs4 import BeautifulSoup import requests import urllib import re import js ...
- [daily]在dark theme下,启动wps的方法
dark之后,wps的字体变成了灰白的 这样启动 env GTK2_RC_FILES=/usr/share/themes/Breeze/gtk-2.0/gtkrc /usr/bin/et -style ...
- Python cffi学习(二)
上篇文章中讲到Python中调用外部c文件可以有两种方法,一是使用cffi.verify()的形式使用,但是该种方式仍然需要进行函数声明.二是将外部c文件编译成为函数库,然后通过cffi进行使用. 由 ...
- 15.2-uC/OS-III资源管理(信号量)
1.信号量 信号量是一个“ 锁定机构”,代码需要获得钥匙才可以访问共享资源.占用该资源的任务不再使用该资源并释放资源时,其它任务才能够访问这个资源. 通常有两种类型的信号量:二值信号量和多值信号量. ...
- SpringBoot-将servlet容器变成undertow测试tomcat吞吐量
将Servlet容器变成Undertow 默认情况下,Spring Boot 使用 Tomcat 来作为内嵌的 Servlet 容器 可以将 Web 服务器切换到 Undertow 来提高应用性能.U ...
- [js]作用域链查找规则获取值和设置值
作用域链查找规则获取值和设置值 <script> /** 1.作用域链查找规则 私有作用域出现的一个变量不是私有的,则往上一级作用域查找,上级作用域没有则继续向上级查找,一直找到windo ...