golang学习笔记——接口interfaces

文章目录

  • Go 语言接口
  • 例子
  • 空接口
    • 空接口的定义
    • 空接口的应用
      • 空接口作为函数的参数
      • 空接口作为map的值
  • 类型断言
    • 接口值
  • 类型断言例子001
  • 类型断言例子002
  • 类型断言例子003
  • 巩固练习

Go 语言接口

接口(interface)定义了一个对象的行为规范,只定义规范不实现,由具体的对象来实现规范的细节。
interface是一组method的集合,是duck-type programming的一种体现。接口做的事情就像是定义一个协议(规则),只要一台机器有洗衣服和甩干的功能,我就称它为洗衣机。不关心属性(数据),只关心行为(方法)。

为了保护你的Go语言职业生涯,请牢记接口(interface)是一种类型。

interface类型可以定义一组方法,但是不需要实现。并且接口(interface)不能包含任何变量

在这里插入图片描述
实例

/* 定义接口 */
type interface_name interface {method_name1 [return_type]method_name2 [return_type]method_name3 [return_type]...method_namen [return_type]
}/* 定义结构体 */
type struct_name struct {/* variables */
}/* 实现接口方法 */
func (struct_name_variable struct_name) method_name1() [return_type] {/* 方法实现 */
}
...
func (struct_name_variable struct_name) method_namen() [return_type] {/* 方法实现*/
}

例子

Go 中的接口是满足隐式实现的(这一点是非常坑人的,建议阅读 Go语言令人厌恶的设计)。 Go 不提供用于实现接口的关键字。

package mainimport ("fmt""math"
)func main() {var s Shape = Square{3}printInformation(s)c := Circle{6}printInformation(c)
}//打印面积和周长
func printInformation(s Shape) {fmt.Printf("%T\n", s)fmt.Println("Area: ", s.Area())fmt.Println("Perimeter:", s.Perimeter())fmt.Println()
}//---Shape 形状---
type Shape interface {//周长Perimeter() float64//面积Area() float64
}//---Square 正方形---
type Square struct {size float64
}func (s Square) Area() float64 {return s.size * s.size
}func (s Square) Perimeter() float64 {return s.size * 4
}//---Circle 圆形---
type Circle struct {radius float64
}func (c Circle) Area() float64 {return math.Pi * c.radius * c.radius
}func (c Circle) Perimeter() float64 {return 2 * math.Pi * c.radius
}

输出

main.Square
Area:  9
Perimeter: 12main.Circle
Area:  113.0973
Perimeter: 37.6991

空接口

空接口的定义

空接口是指没有定义任何方法的接口。因此任何类型都实现了空接口。

空接口类型的变量可以存储任意类型的变量。

func main() {// 定义一个空接口xvar x interface{}s := "pprof.cn"x = sfmt.Printf("type:%T value:%v\n", x, x)i := 100x = ifmt.Printf("type:%T value:%v\n", x, x)b := truex = bfmt.Printf("type:%T value:%v\n", x, x)
}

空接口的应用

空接口作为函数的参数

使用空接口实现可以接收任意类型的函数参数。

// 空接口作为函数参数
func show(a interface{}) {fmt.Printf("type:%T value:%v\n", a, a)
} 

空接口作为map的值

使用空接口实现可以保存任意值的字典。

// 空接口作为map值var studentInfo = make(map[string]interface{})studentInfo["name"] = "李白"studentInfo["age"] = 18studentInfo["married"] = falsefmt.Println(studentInfo) 

类型断言

空接口可以存储任意类型的值,那我们如何获取其存储的具体数据呢?

接口值

一个接口的值(简称接口值)是由一个具体类型和具体类型的值两部分组成的。这两部分分别称为接口的动态类型和动态值。

我们来看一个具体的例子:

var w io.Writer
w = os.Stdout
w = new(bytes.Buffer)
w = nil 

请看下图分解:
在这里插入图片描述
想要判断空接口中的值这个时候就可以使用类型断言,其语法格式:

    x.(T) 

其中:

    x:表示类型为interface{}的变量T:表示断言x可能是的类型。

该语法返回两个参数,第一个参数是x转化为T类型后的变量,第二个值是一个布尔值,若为true则表示断言成功,为false则表示断言失败。

举个例子:

func main() {var x interface{}x = "pprof.cn"v, ok := x.(string)if ok {fmt.Println(v)} else {fmt.Println("类型断言失败")}
} 

上面的示例中如果要断言多次就需要写多个if判断,这个时候我们可以使用switch语句来实现:

func justifyType(x interface{}) {switch v := x.(type) {case string:fmt.Printf("x is a string,value is %v\n", v)case int:fmt.Printf("x is a int is %v\n", v)case bool:fmt.Printf("x is a bool is %v\n", v)default:fmt.Println("unsupport type!")}
} 

因为空接口可以存储任意类型值的特点,所以空接口在Go语言中的使用十分广泛。

关于接口需要注意的是,只有当有两个或两个以上的具体类型必须以相同的方式进行处理时才需要定义接口。不要为了接口而写接口,那样只会增加不必要的抽象,导致不必要的运行时损耗。

类型断言例子001

类型断言也可以判断指针类型

package mainimport "fmt"func main() {var n1 int32 = 30var n2 string = "tomcat"n3 := falsestu1 := Student{}stu2 := &Student{}justifyType(n1,n2,n3,stu1,stu2)
}type Student struct {}func justifyType(items ...interface{}) {for index, x := range items {switch v := x.(type) {case string:fmt.Printf("第%v个参数是 string 类型,值是 %v\n",index,v)case int:fmt.Printf("第%v个参数是 int 类型,值是 %v\n",index,v)case bool:fmt.Printf("第%v个参数是 bool 类型,值是 %v\n",index,v)case Student:fmt.Printf("第%v个参数是 Student 类型,值是 %v\n",index,v)case *Student:fmt.Printf("第%v个参数是 *Student 类型,值是 %v\n",index,v)default:fmt.Println("unsupport type!")}}
} 

类型断言例子002

package mainimport "fmt"func main() {var i interface{} = "Hello, World"str, ok := i.(string)if ok {fmt.Printf("'%s' is a string\n", str)} else {fmt.Println("conversion failed")}
}

类型断言例子003

给Phone结构体一个特有的方法Call(),当Usb接口接收的是Phone变量时,还需要调用call方法

package mainimport "fmt"func main() {//定义一个usb接口数组,可以存放Phone和Camera的结构体变量// 这里就体现出多态数组var usbArr [3]UsbusbArr[0] = Phone{"vivo"}usbArr[1] = Phone{"小米"}usbArr[2] = Camera{"惠普"}//遍历usbArrvar computer Computerfor _, v := range usbArr {computer.Working(v)}
}type Usb interface {Start()Stop()
}type Camera struct {name string		
}type Phone struct {name string
}type Computer struct {name string
}func (c Camera) Start() {fmt.Println("相机开始工作...")
}func (c Camera) Stop() {fmt.Println("相机停止工作...")
}func (p Phone) Start() {fmt.Printf("%s 手机开始工作...\n", p.name )
}func (p Phone) Stop() {fmt.Printf("%s 手机停止工作...\n", p.name )
}func (p Phone) Call() {fmt.Println("手机 打电话")
}func (computer Computer) Working(usb Usb) {usb.Start()if phone, ok := usb.(Phone); ok {phone.Call()}usb.Stop()
}

巩固练习

  1. 在Go语言中,接口是什么?请解释其含义。
  2. 如何定义一个接口?解释接口定义的基本语法。
  3. Go语言中的接口实现是如何工作的?请详细解释。
  4. 什么是空接口?它有什么用途?
  5. 能否给出一些使用接口的例子?这些例子中接口的作用是什么?
  6. Go语言不同接口、声明了同名方法,怎么解决问题?

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/198042.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Java面向对象(高级)-- 类的成员之四:代码块

文章目录 一、回顾(1)三条主线(2)类中可以声明的结构及作用1.结构2.作用 二、代码块(1)代码块的修饰与分类1. 代码块的修饰2. 代码块的分类3. 举例 (2) 静态代码块1. 语法格式2. 静态…

【数据结构】栈与队列面试题(C语言)

我们再用C语言做题时,是比较不方便的,因此我们在用到数据结构中的某些时只能手搓或者Ctrlcv 我们这里用到的栈或队列来自栈与队列的实现 目录 有效的括号解题思路:代码实现: 用队列实现栈解题思路:代码实现&#xff1a…

4月2日-3日·上海 | 3DCC 第二届3D细胞培养与类器官研发峰会携手CGT Asia 重磅来袭

类器官(Organoids)作为干细胞研究领域最重要的成果之一,在基础医学研究、转化医学及药物研发领域展现出巨大的应用潜力,特别是在精准医疗以及药物安全性和有效性评价等方向凭借其先天优势引起了极大的市场关注,成为各大…

LabVIEW进行MQTT通信及数据解析

需求:一般通过串口的方式进行数据的解析,但有时候硬件的限制,没法预留串口,那么如何通过网络的方式特别是MQTT数据的通信及解析 解决方式: 1.MQTT通信控件: 参考开源的mqtt-LabVIEW https://github.com…

【iOS】——知乎日报第五周总结

文章目录 一、评论区展开与收缩二、FMDB库实现本地持久化FMDB常用类:FMDB的简单使用: 三、点赞和收藏的持久化 一、评论区展开与收缩 有的评论没有被回复评论或者被回复评论过短,这时就不需要展开全文的按钮,所以首先计算被回复评…

量化交易:借助talib使用技术分析指标

什么是技术分析? 所谓股票的技术分析,是相对于基本面分析而言的。基本分析法着重于对一般经济情况以及各个公司的经营管理状况、行业动态等因素进行分析,以此来研究股票的价值,衡量股价的高低。而技术分析则是透过图表或技术指标…

vulhub redis-4-unacc

环境搭建 cd vulhub/redis/4-unacc docker-compose up -d 漏洞复现 检测 redis-cli -h ip 使用redis工具 工具地址:https://github.com/vulhub/redis-rogue-getshell 下载完成后,先进入RedisModulesSDK/exp/ 目录进行make操作 获得exp.so后可以进行…

Jenkinsfile+Dockerfile前端vue自动化部署

前言 本篇主要介绍如何自动化部署前端vue项目 其中,有两种方案: 第一种是利用nginx进行静态资源转发;第二种方案是利用nodejs进行启动访问; 各个组件版本如下: Docker 最新版本;Jenkins 2.387.3nginx …

物联网AI MicroPython学习之语法 I2C总线

学物联网,来万物简单IoT物联网!! I2C 介绍 模块功能: I2C Master设备驱动 接口说明 I2C - 构建硬件I2C对象 函数原型:I2C(id, scl, sda, freq)参数说明: 参数类型必选参数?说明idintYI2C外设&#xff…

带你快速掌握Linux最常用的命令(图文详解)- 最新版(面试笔试常考)

最常用的Linux指令(图文详解)- 最新版 ls:列出目录中的文件和子目录(重点)cd:改变当前工作目录绝对路径:相对路径 pwd:显示当前工作目录的路径mkdir:创建一个新的目录tou…

【开源】基于Vue.js的音乐偏好度推荐系统的设计和实现

项目编号: S 012 ,文末获取源码。 \color{red}{项目编号:S012,文末获取源码。} 项目编号:S012,文末获取源码。 目录 一、摘要1.1 项目介绍1.2 项目录屏 二、系统设计2.1 功能模块设计2.1.1 音乐档案模块2.1…

spring中的DI

【知识要点】 控制反转(IOC)将对象的创建权限交给第三方模块完成,第三方模块需要将创建好的对象,以某种合适的方式交给引用对象去使用,这个过程称为依赖注入(DI)。如:A对象如果需要…

代码随想录算法训练营Day 54 || 392.判断子序列、115.不同的子序列

392.判断子序列 力扣题目链接(opens new window) 给定字符串 s 和 t ,判断 s 是否为 t 的子序列。 字符串的一个子序列是原始字符串删除一些(也可以不删除)字符而不改变剩余字符相对位置形成的新字符串。(例如,&quo…

多svn仓库一键更新脚本分享

之前分享过多git仓库一键更新脚本,本期就分享下svn仓库的一键更新脚本 1、首先需要设置svn为可执行命令行 打开SVN安装程序,选择modify,然后点击 command client tools,安装命令行工具 2、update脚本 echo 开始更新SVN目录&…

计算机视觉:使用opencv实现车牌识别

1 引言 汽车车牌识别(License Plate Recognition)是一个日常生活中的普遍应用,特别是在智能交通系统中,汽车牌照识别发挥了巨大的作用。汽车牌照的自动识别技术是把处理图像的方法与计算机的软件技术相连接在一起,以准…

Linux管道的工作过程

常用的匿名管道(Anonymous Pipes),也即将多个命令串起来的竖线。管道的创建,需要通过下面这个系统调用。 int pipe(int fd[2]) 我们创建了一个管道 pipe,返回了两个文件描述符,这表示管道的两端&#xff…

jvm 内存结构 ^_^

1. 程序计数器 2. 虚拟机栈 3. 本地方法栈 4. 堆 5. 方法区 程序计数器 定义: Program Counter Register 程序计数器(寄存器) 作用,是记住下一条jvm指令的执行地址 特点: 是线程私有的 不会存在内存溢出 虚拟机栈…

SQL练习02

1.买下所有产品的客户 SQL Create table If Not Exists Customer (customer_id int, product_key int); Create table Product (product_key int); Truncate table Customer; insert into Customer (customer_id, product_key) values (1, 5); insert into Customer (customer_…

开源供应链管理系统 S2B2B2C系统方案及源码输出

这个开源供应链管理系统提供针对企业供应链管理需求的开放源代码解决方案。通过开源供应链管理系统,企业能够实现对供应商、进销存和物流配送等方面的全面管理和优化,涵盖了从供应商选择到门店到消费者服务交付的整个流程。开源系统使企业能够根据自身需…

Linux|僵死进程

1.僵死进程产生的原因或者条件: 什么是僵死进程? 当子进程先于父进程结束,父进程没有获取子进程的退出码,此时子进程变成僵死进程. 简而言之,就是子进程先结束,并且父进程没有获取它的退出码; 那么僵死进程产生的原因或者条件就是:子进程先于父进程结束,并且父进程没有获取…