接口作用

   Go语言中的接口是一种类型,类似于Python中的抽象基类。

   Go语言中使用接口来体现多态,是duck-type的一种体现。

   如,只要一个东西会叫,会走,那么我们就可以将它定义为一个动物的接口。

接口定义

   Go中提倡面向接口编程,以下是接口的定义。

type 接口类型名 interface{
方法名1( 参数列表1 ) 返回值列表1
方法名2( 参数列表2 ) 返回值列表2

}

   关于接口的定义有以下几点注意事项:

   接口名在单词后面一般都需添加er的后缀,代表这是一个接口

   当接口名与方法名都是大写时,代表该接口与方法均可被外部包进行访问

   参数列表以及返回值列表参数变量名可以省略

   以下我们将定义一个动物的接口,会叫,会移动我们将将它看作为动物。

   并且我们为该接口定义了一个方法撒泼,只要是动物就可以进行撒泼。

package main

import (
"fmt"
) type animal interface {
move()
roar()
} func sapo(a animal){ // 接收一个动物类型
a.move()
a.roar()
}

接口使用

   如何使用上面的接口呢?其实我们还需要做结构体。

   如下示例,做了一个狗的结构体和一个狼的结构体并且进行实例化,由于狗和狼都实现了move以及roar方法,所以这两个实例化都可以看作是animal类型,即可以调用sapo方法。

package main

import (
"fmt"
) type animal interface {
move()
roar()
} func sapo(a animal){
a.move()
a.roar()
} type dog struct {
name string } func (d dog) move() {
fmt.Printf("%s在移动\n", d.name)
} func (d dog) roar() {
fmt.Printf("%s在吼叫\n", d.name)
} type wolf struct {
name string } func (w wolf) move() {
fmt.Printf("%s在移动\n", w.name)
} func (w wolf) roar() {
fmt.Printf("%s在吼叫\n", w.name)
} func main() {
d1 := dog{
name: "大黄",
}
w1 := wolf{
name: "灰太狼",
}
sapo(d1) // 大黄调用动物的撒泼方法,由于会动会叫就是动物,所以大黄有两种类型,一种是动物,一种是狗
sapo(w1)
} // 大黄在移动
// 大黄在吼叫
// 灰太狼在移动
// 灰太狼在吼叫

接口变量

   接口是一种类型,所以一个变量可以定义为该类型。

   如下所示,声明了一个动物类型的接口变量,当一个结构体实例对象拥有了moveroar方法后,才可成功进行赋值。

package main

import (
"fmt"
) type animal interface {
move()
roar()
} type dog struct {
name string
} func (d dog) move() {
fmt.Printf("%s在移动\n", d.name)
} func (d dog) roar() {
fmt.Printf("%s在吼叫\n", d.name)
} func main() {
var a1 animal // 动物类型
d1 := dog{
name: "大黄",
}
a1 = d1 // 由于大黄有move与roar方法,所以它也算是动物类型。因此可以赋值成功
a1.move()
}

结构体方法类型

   结构体不同的方法类型,会对接口产生不同的影响。

值接收者方法

   当结构体的方法是值接收者方法时,该结构体实例化可以赋值给对应的接口变量,并且是任意形式。

package main

import (
"fmt"
) type people interface {
combHair() // 能梳头就是人
} type person struct {
name string
} // 值接收者方法
func (p person) combHair() {
fmt.Printf("%s在梳头发", p.name)
} func main() {
var pe people // 人类
var p1 = person{
name: "云崖",
} // 全部都可以做为人类
pe = p1
pe = &p1
pe = *(&p1)
fmt.Println(pe)
}

指针接收者方法

   当结构体的方法是指针接收者方法时,该结构体实例化赋值给接口变量时只能是地址传递。

package main

import (
"fmt"
) type people interface {
combHair() // 能梳头就是人
} type person struct {
name string
} // 指针接收者方法
func (p *person) combHair() {
fmt.Printf("%s在梳头发", p.name)
} func main() {
var pe people // 人类
var p1 = person{
name: "云崖",
} pe = *p1 // 错误
pe = &p1 // 只能传递地址
pe = *(&p1) // 错误
fmt.Println(pe)
}

类型与接口

一个类型多个接口

   如会梳头发是人类,会移动是动物类。

   那么我们就可以对person这个结构体做两个接口,一个是人类的接口,一个是动物类的接口。

   person实例化对象p1同时满足人类和动物这两个接口。

package main

import (
"fmt"
) type people interface {
combHair() // 能梳头就是人
} type animal interface {
move() // 能移动就是动物
} type person struct {
name string
} func (p person) move() {
fmt.Println("人移动了")
} func (p person) combHair(){
fmt.Println("人在梳头发")
} func main() {
var pe people // 人类接口变量
var an animal // 动物接口变量
var p1 = person{ // 实例化出一个人
name: "云崖",
} pe = p1
an = p1
fmt.Println(pe)
fmt.Println(an)
}

一个接口多个类型

   如会动的都是动物,那么下面例子中狗和牛等结构体的实例化就都是动物。

   这就是一个动物接口可以有多个类型的体现。

package main

import (
"fmt"
) type people interface {
combHair() // 能梳头就是人
} type animal interface {
move() // 能移动就是动物
} type dog struct {
name string
} type cattle struct {
name string
} func (d dog) move() {
fmt.Println("狗在动")
} func (c cattle) move() {
fmt.Println("牛在动")
} func main() {
var an animal // 动物接口变量 d1 := dog{
name: "大黄",
}
c1 := cattle{
name: "牛魔王",
}
an = d1
fmt.Println(an)
an = c1
fmt.Println(an)
}

接口嵌套

   比如两栖动物可以在水中生活,也可以在陆地生活。

   我们定义一个陆地生活动物的接口,再定义一个水中生活动物的接口。

   如何表示两栖动物的接口呢?只需要应用嵌套让两栖动物的接口同时拥有陆地生活动物接口的方法和水中生活动物的方法即可。

   如下示例:

package main

import (
"fmt"
) type terrestrialAnimal interface {
landMobile() // 陆地移动,则是陆生动物
} type aquatic interface {
swim() // 能够游泳,则是水生动物
} type amphibian interface {
terrestrialAnimal
aquatic
// 同时实现了陆生动物和水生动物的特性,则是两栖动物
} type frog struct{
name string
// 青蛙结构体
} // 青蛙会游泳
func (f frog) swim(){
fmt.Println("青蛙在游泳")
} // 青蛙能上岸
func (f frog) landMobile(){
fmt.Println("青蛙在陆地上欢快的蹦跶")
} func main() {
var amp amphibian // 两栖动物接口变量
var f1 = frog {
name : "呱呱娃",
}
amp = f1 // 青蛙是两栖动物
fmt.Println(amp) }

空接口

   空接口在实际开发中使用非常广泛,它代表可以是任意类型的变量。

接口定义

   使用interface{}来定义一个空接口。

   如下所示:

package main

import (
"fmt"
) func main(){
var arbitraryType interface{} // 接收任意类型的变量
var str = "HELLO,WORLD"
arbitraryType = str
fmt.Printf("%T \n", arbitraryType) // string
var num = int64(100)
arbitraryType = num
fmt.Printf("%T \n",arbitraryType) // int64 }

实际应用

   空接口一般应用于函数形参,以及map值中。

   如下,该函数允许传递任何数据类型的数据。

package main

import (
"fmt"
) func test(v1 interface{}) {
fmt.Printf("%T \n", v1) // int
} func main() {
test(100)
}

   其实更多的应用场景在map中,如下定义的map值可以是任意类型,这样存取都会变得很方便。

package main

import (
"fmt"
) var m = make(map[string]interface{}, 30) func main() {
m["k1"] = "第一个"
m["k2"] = 2
m["k3"] = []int16{1,2,3,4}
fmt.Print(m)
}

类型断言

   由于interface{}空接口可以存储任意类型的值,那么我们如何判断出值的类型?

   方法如下:

x.(T)

   x:表示类型为interface{}的变量

   T:表示断言x可能是的类型。

   方法断言的作用其实就类似于猜,这种用的不是很多。

   如下示例,使用switch进行类型断言的判断:

package main

import (
"fmt"
) var m = make(map[string]interface{}, 30) func test(v1 map[string]interface{}) {
for _, value := range v1 {
switch value.(type) { // 使用断言获取到类型
case string:
fmt.Println("这是一个字符串类型", value)
case int:
fmt.Println("这是一个int类型", value)
case []int16:
fmt.Println("这是一个int16的切片类型", value)
default:
fmt.Println("未识别的类型", value)
}
}
} func main() {
m["k1"] = "第一个"
m["k2"] = 2
m["k3"] = []int16{1, 2, 3, 4}
test(m)
}

Go 接口类型的更多相关文章

  1. 无法将类型为“Microsoft.Office.Interop.Word.ApplicationClass”的 COM 对象强制转换为接口类型“Microsoft.Office.Interop.Word._Application”。

    无法将类型为“Microsoft.Office.Interop.Word.ApplicationClass”的 COM 对象强制转换为接口类型“Microsoft.Office.Interop.Wor ...

  2. (转)无法将类型为“Microsoft.Office.Interop.Word.ApplicationClass”的 COM 对象强制转换为接口类型“Microsoft.Office.Interop.Word._Application”。此操作失败的原因是对 IID 为“{00020970-

    HRESULT:0x80030002 无法将类型为“Microsoft.Office.Interop.Word.ApplicationClass”的 COM 对象强制转换为接口类型“Microsoft ...

  3. 无法将类型为 excel.applicationclass 的 com 强制转换为接口类型 的解决方法。

    今天碰到客户的电脑在导出EXCEL的时候提示,无法将类型为 excel.applicationclass 的 com 强制转换为接口类型 excel._application 的问题 最后用下面的方法 ...

  4. C#与excel互操作的错误无法将类型为“Excel.ApplicationClass”的COM 对象强制转换为接口类型“Excel._Application”

    如果您使用的电脑要操作的是office2003而之前使用过office2007使用此方法可解决您的问题 无法将类型为“Microsoft.Office.Interop.Excel.Applicatio ...

  5. 无法将类型为“System.__ComObject”的 COM 对象强制转换为接口类型,原因为没有注册类

    错误描述 e = {"无法将类型为"System.__ComObject"的 COM 对象强制转换为接口类型"OpcRcw.Da.IOPCServer" ...

  6. System.InvalidCastException: 无法将类型为“Microsoft.Office.Interop.Word.ApplicationClass”的 COM 对象强制转换为接口类型“Microsoft.Office.Interop.Word._Application”。

    报错:System.InvalidCastException: 无法将类型为“Microsoft.Office.Interop.Word.ApplicationClass”的 COM 对象强制转换为接 ...

  7. 无法将类型为excel.applicationclass的com 强制转换为接口类型的解决方法[转]

    c#解决方案EXCEL 导出 今天碰到客户的电脑在导出EXCEL的时候提示,无法将类型为 excel.applicationclass 的 com 强制转换为接口类型 excel._applicati ...

  8. Go基础系列:接口类型断言和type-switch

    接口类型探测:类型断言 接口实例中存储了实现接口的类型实例,类型的实例有两种:值类型实例和指针类型实例.在程序运行过程中,接口实例存储的实例类型可能会动态改变.例如: // ins是接口实例 var ...

  9. Go语言规格说明书 之 接口类型(Interface types)

    go version go1.11 windows/amd64 本文为阅读Go语言中文官网的规则说明书(https://golang.google.cn/ref/spec)而做的笔记,介绍Go语言的  ...

  10. mocha测试接口类型及测试报告收集

    记录参考: 参考文档: 测试报告以及es6: http://www.ruanyifeng.com/blog/2015/12/a-mocha-tutorial-of-examples.html 测试接口 ...

随机推荐

  1. 关于js重名方法的先后调用问题

    当js中方法重名时,最后引入的js会覆盖前面的引入的js(就是说会调用最后引入的js中的方法)详情参照(main.js与white.js 的a())但是,当最后一个js中存在语法上的错误时(也可以是本 ...

  2. MySQL 数据库中的基础操作

    数据库中的表操作 1.创建表 表的表名命名规则: -- 数据库表命名规则重要说明: -- (1)数据库表名称可以支持大写字母A-Z,小写字母a-z,数字0-9,字符包括下划线 _ ,可以组合使用; - ...

  3. FZU - 2038 -E - Another Postman Problem (思维+递归+回溯)

    Chinese Postman Problem is a very famous hard problem in graph theory. The problem is to find a shor ...

  4. 深入了解Redis【一】源码下载与参考资料准备

    引言 一直在使用redis,但是却没有系统的了解过它的底层实现,准备边学习边记录,深入了解redis. 打算分析以下几个方面: redis的基本类型及底层原理与java对比,每种数据类型的使用场景 r ...

  5. Netty进阶和实战

    实现UDP单播和广播 UDP 这样的无连接协议中,并没有持久化连接这样的概念,并且每个消息(一个UDP 数据报)都是一个单独的传输单元.此外,UDP 也没有TCP 的纠错机制. 通过类比,TCP 连接 ...

  6. [LeetCode]26. 删除排序数组中的重复项(数组,双指针)

    题目 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度. 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下 ...

  7. 初等函数——指数函数(Exponential Function)

    一般地,函数叫做指数函数,其中x是自变量,函数的定义域是R.

  8. STL_Vector(向量)

    向量Vector 头文件 #include<vector> 作用: vector是一种顺序容器,与数组类似,但与之不同的是vector并不需要开辟内存空间,其类似于每存一个变量便开一个空间 ...

  9. 原来写插件还可以选MEF

    MEF是微软提供的一个轻量级的ICO容器,可以轻易的解除程序集的依赖关系,最近想写个类似插件试的软件所以搜索了一下,终于淘到宝了. 下面我们看看MEF是如何解耦的 新建一个控制台项目两个类库 Ites ...

  10. (数据科学学习手札95)elyra——jupyter lab平台最强插件集

    本文示例文件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 jupyter lab是我最喜欢的编辑器,在过往 ...