Golang笔记——Interface类型
大家好,这里是,关注 公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Golang的interface数据结构类型,包括基本实现和使用等。

文章目录
- Go 语言中的 `interface` 详解
- 接口定义
- 实现接口
- 空接口 `interface{}`
- 示例:空接口的使用
- interface 类型判断
- 1. 类型断言(Type Assertion)
- 语法
- 示例
- 类型转换和类型断言的区别
- 2. 类型开关(Type Switch)
- 语法
- 示例
- 3. 反射(Reflection)
- 示例
- 反射的关键点
- 总结
- 接口与多态
- 解释
- 接口的嵌套
- 示例
- 总结
- 历史文章
- MySQL数据库
- Redis
- Golang
Go 语言中的 interface 详解
Go 语言中的 interface 是一种强大且灵活的类型系统机制,它使得 Go 能够实现类似面向对象语言多态的特性。接口是一组方法签名的集合,而接口类型定义了某些行为,任何类型只要实现了接口中的方法,就自动成为该接口的实现类型。
简单的说,interface主要表现在以下几个方面:
- 方法的集合:接口是方法的集合,定义了一个类型需要实现哪些方法,但不关心实现的具体细节。只要一个类型实现了接口中的方法,就被认为实现了这个接口。
- 多态实现:接口的核心作用之一是实现多态。在 Go 中,不同类型只要实现了相同的接口方法,就可以通过接口来统一处理,达到灵活的多态性。这使得我们可以编写更加解耦和可扩展的代码。
- 空接口
interface{}是一种变量类型:接口是 Go 中的一个类型,空接口(interface{}) 是最基础的接口类型,它可以存储任何类型的值。实际上它是一个由两部分组成的结构体:- 类型(Dynamic Type):接口变量所保存值的具体类型。
- 值(Dynamic Value):接口变量所保存的具体值。
在 Go 中,接口是非常核心的概念,它帮助我们编写解耦、灵活、可扩展的代码。
接口定义
接口定义了类型应该具备的行为(即方法)。Go 的接口与其他语言(如 Java 或 C++)中的接口有一些不同之处,特别是Go 的接口不需要显式声明实现,即只要类型实现了接口的方法,就自动实现了该接口。
type InterfaceName interface {Method1() // 方法签名Method2() // 方法签名
}
实现接口
Go 不要求显式声明某个类型实现了一个接口,只要该类型实现了接口中声明的所有方法,它就自然地“实现”了该接口。接口与类型之间的关系是隐式的。
package mainimport "fmt"// 定义接口
type Speaker interface {Speak() // 定义接口中的方法
}// 定义结构体
type Person struct {Name string
}// Person 实现了 Speaker 接口的 Speak 方法
func (p Person) Speak() {fmt.Println("Hello, my name is", p.Name)
}func main() {// 创建 Person 类型的实例p := Person{Name: "Alice"}// 将 p 赋给接口类型 Speakervar speaker Speaker = p// 调用接口的方法speaker.Speak() // 输出:Hello, my name is Alice
}
说明:
Speaker接口有一个方法Speak。Person类型实现了Speak方法,因此它自动实现了Speaker接口。- 在
main函数中,p被赋给了接口类型Speaker,然后调用接口的方法Speak。
空接口 interface{}
空接口 interface{} 是一个特殊的接口类型,它没有定义任何方法。由于任何类型都实现了空接口。空接口通常用于存储任何类型的值,类似于其他语言中的 Object 类型。
示例:空接口的使用
package mainimport "fmt"func main() {var x interface{} // 声明一个空接口x = 42 // x 可以存储 intfmt.Println(x) // 输出:42x = "Hello" // x 可以存储 stringfmt.Println(x) // 输出:Hellox = 3.14 // x 可以存储 float64fmt.Println(x) // 输出:3.14
}
interface 类型判断
在 Go 中,由于接口类型是通用的,它可以存储任何实现了该接口的类型,因此在使用接口时,可能并不知道它具体存储的是哪个类型的值。为了处理这种不确定性,Go 提供了三种常用的机制来检测或转换接口的实际类型:
- 类型断言(Type Assertion)
- 类型开关(Type Switch)
- 反射(Reflection)
这三者在 Go 中各有不同的用途,适用于不同的场景。通常情况下,如果你只需要判断一个接口的类型并进行相应处理,类型断言 或 类型开关 是更常见的选择;而 反射 则通常用于更加动态和通用的场景,例如实现框架、库、ORM 等。
下面分别详细介绍这三种机制:
1. 类型断言(Type Assertion)
类型断言用于从接口类型转换回具体类型。它允许我们在运行时检查接口值的动态类型,并进行转换。
语法
value, ok := x.(T)
x是接口类型的变量,T是你想要转换成的具体类型。- 如果
x存储的值是T类型,value将会是存储的值,而ok为true。 - 如果
x存储的值不是T类型,value会是T类型的零值,而ok为false。
示例
package mainimport "fmt"func main() {var a interface{} = 42// 类型断言if v, ok := a.(int); ok {fmt.Println("a is an int:", v)} else {fmt.Println("a is not an int")}
}
输出:
a is an int: 42
类型转换和类型断言的区别
- 类型转换 是编译时的操作,用于在兼容类型之间进行显式转换。它适用于基本类型之间以及自定义类型的转换。
- 类型断言 是运行时的操作,用于从接口类型中提取具体的类型和值。它适用于动态类型判断的场景。
属性
类型转换 (Type Conversion)
类型断言 (Type Assertion)
使用场景
在兼容的类型之间进行显式转换(如 int 转 float64)。
用于从接口类型中提取底层的具体类型和值。
操作时机
编译时。
运行时。
适用范围
基本数据类型、自定义类型等。
接口类型(interface{} 或其他接口)。
结果
将值转换为目标类型。
提取接口的具体值或判断类型是否匹配。
错误处理
不兼容类型转换会导致编译错误。
不安全断言会导致运行时 panic;安全断言返回一个布尔值。
语法
value := T(originalValue)
value, ok := iface.(T) 或 value := iface.(T)
2. 类型开关(Type Switch)
类型开关是 Go 中提供的更强大、更灵活的机制,它允许我们对接口值的类型进行多分支判断。与普通的 switch 语句不同,类型开关的 case 中是基于接口的动态类型进行匹配的。
语法
switch v := x.(type) {
case T1:// x 是 T1 类型
case T2:// x 是 T2 类型
default:// x 是其他类型
}
x.(type)会检查x接口的动态类型。- 你可以根据不同的类型执行不同的逻辑。
示例
package mainimport "fmt"func identifyType(x interface{}) {switch v := x.(type) {case int:fmt.Println("int:", v)case string:fmt.Println("string:", v)default:fmt.Println("unknown type")}
}func main() {identifyType(42) // 输出:int: 42identifyType("hello") // 输出:string: helloidentifyType(3.14) // 输出:unknown type
}
3. 反射(Reflection)
Go 的 reflect 包提供了在运行时操作接口的功能,能够动态地获取接口的具体类型和方法。这是 Go 中非常强大的特性,可以在不知道类型的情况下执行一些操作,例如获取类型的名称、字段信息、调用方法等。
示例
package mainimport ("fmt""reflect"
)type Dog struct{}func (d Dog) Speak() {fmt.Println("Woof!")
}func main() {var a interface{} = Dog{}// 使用反射获取类型t := reflect.TypeOf(a)fmt.Println("Type:", t)// 使用反射获取值v := reflect.ValueOf(a)fmt.Println("Value:", v)// 通过反射调用方法if t.Kind() == reflect.Struct {method := v.MethodByName("Speak")if method.IsValid() {method.Call(nil) // 输出:Woof!}}
}
反射的关键点
reflect.TypeOf()用来获取接口的具体类型。reflect.ValueOf()用来获取接口的具体值。reflect.ValueOf(a).MethodByName("MethodName")可以动态调用结构体的方法。
总结
- 类型断言:用于在运行时提取接口的具体类型值,如果类型不匹配,可以使用
ok变量避免运行时错误。 - 类型开关:允许你对接口值的动态类型进行多分支判断,可以在多个可能的类型之间选择。
- 反射:通过
reflect包可以在运行时获取接口的类型和值,甚至可以动态地调用方法或修改值。
接口与多态
Go 语言的多态是通过接口实现的。接口提供了一种方法,让不同类型的对象能以统一的方式来调用它们的行为。
package mainimport "fmt"type Animals interface {Say()
}type Dog struct{}
type Cat struct{}func (d Dog) Say() {fmt.Println("wangwang")
}func (c Cat) Say() {fmt.Println("miaomiao")
}func main() {var d Dogd.Say() // 输出:wangwangvar c Catc.Say() // 输出:miaomiao// 使用接口变量1,可以接受任何实现了 Say() 方法的类型var a Animalsa = da.Say() // 输出:wangwanga = ca.Say() // 输出:miaomiao// 使用接口变量2,可以接受任何实现了 Say() 方法的类型var a1 Animalsa1 = Dog{}a1.Say() // 输出:wangwanga1 = Cat{}a1.Say() // 输出:miaomiao
}
解释
Dog和Cat都实现了Animals接口。a是一个接口类型,可以存储任何实现了Say方法的类型。- 通过多态,我们可以使用同一个接口变量
a存储不同的类型,并调用它们各自的Say方法。
接口的嵌套
Go 允许接口嵌套,接口可以继承其他接口的方法。当一个接口嵌套另一个接口时,它自动包含了被嵌套接口的方法。
示例
package mainimport "fmt"// 定义 Animal 接口
type Animal interface {Speak()
}// 定义 Worker 接口,嵌入 Animal 接口
type Worker interface {Animal // Animal 接口被嵌套在 Worker 接口中Work()
}// 定义 Dog 结构体
type Dog struct{}// Dog 实现了 Animal 接口的 Speak 方法
func (d Dog) Speak() {fmt.Println("wangwang")
}// Dog 实现了 Worker 接口的 Work 方法
func (d Dog) Work() {fmt.Println("Dog is working!")
}func main() {// 创建 Dog 类型的对象var w Worker = Dog{}// 调用 Worker 接口的方法w.Speak() // 输出:wangwangw.Work() // 输出:Dog is working!
}
-
接口嵌套:
Worker接口通过Animal接口嵌套了Speak方法,这意味着Worker接口需要实现Speak和Work方法。 -
Dog 类型实现接口:
Dog类型实现了Speak和Work方法,满足了Worker接口的要求。 -
接口引用:在
main函数中,w是Worker类型的接口变量,它引用了Dog类型的对象。由于Dog类型实现了Speak和Work方法,所以可以调用w.Speak()和w.Work()。
总结
- Go 中的接口:接口是一组方法签名的集合,Go 语言通过接口实现了多态。
- 隐式实现:Go 中不需要显式声明类型实现接口,任何实现了接口方法的类型都会自动实现该接口。
- 空接口:
interface{}可以存储任何类型的值,类似于其他语言中的Object类型。 - 类型断言:允许从接口类型转换回具体类型,提供灵活的运行时类型检查。
- 接口与多态:通过接口,Go 实现了动态多态,允许不同类型通过统一的接口调用各自的行为。
接口是 Go 语言的核心特性之一,它使得 Go 在保持简洁和灵活性的同时,支持面向对象的编程风格。
历史文章
MySQL数据库
MySQL数据库
Redis
Redis数据库笔记合集
Golang
- Golang笔记——语言基础知识
- Golang笔记——切片与数组
- Golang笔记——hashmap
- Golang笔记——rune和byte
- Golang笔记——channel
相关文章:
Golang笔记——Interface类型
大家好,这里是,关注 公主号:Goodnote,专栏文章私信限时Free。本文详细介绍Golang的interface数据结构类型,包括基本实现和使用等。 文章目录 Go 语言中的 interface 详解接口定义实现接口空接口 interface{} 示例&…...
如何查看图片的原始格式
问题描述:请求接口的时候,图片base64接口报错,使用图片url请求正常 排查发现是图片格式的问题: 扩展名可能被篡改:如果文件损坏或扩展名被手动修改,实际格式可能与显示的不同,需用专业工具验证…...
FreiHAND (handposeX-json 格式)数据集-release >> DataBall
FreiHAND (handposeX-json 格式)数据集-release 注意: 1)为了方便使用,按照 handposeX json 自定义格式存储 2)使用常见依赖库进行调用,降低数据集使用难度。 3)部分数据集获取请加入:DataBall-X数据球(free) 4)完…...
【Rust中级教程】2.8. API设计原则之灵活性(flexible) Pt.4:显式析构函数的问题及3种解决方案
喜欢的话别忘了点赞、收藏加关注哦(加关注即可阅读全文),对接下来的教程有兴趣的可以关注专栏。谢谢喵!(・ω・) 说句题外话,这篇文章一共5721个字,是我截至目前写的最长的一篇文章&a…...
LabVIEW Browser.vi 库说明
browser.llb 库位于C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform目录,它是 LabVIEW 平台下用于与网络浏览器相关操作的重要库。该库为 LabVIEW 开发者提供了一系列工具,用于实现网页浏览控制、网页数据获取与交互等功能&a…...
promise的方法有哪些?【JavaScript】
Promise对象在JavaScript中是一种处理异步操作的方式,它提供了一组方法来管理和控制异步操作的结果。以下是一些常用的Promise方法: 以下是对 constructor(executor)、then(onFulfilled, onRejected)、catch(onRejected)、 finally(onFin…...
基于模仿学习(IL)的端到端自动驾驶发展路径
基于模仿学习(IL)的端到端自动驾驶发展路径 1. 核心论文解析 (1) UniAD:感知-规划一体化 核心思想:首次提出将感知任务(如目标检测、车道线识别、轨迹预测)与规划任务集成到统一的端到端框架中ÿ…...
第1篇:SOLR 简介与源码环境搭建
第1篇:SOLR 简介与源码环境搭建 1.1 SOLR 是什么? Apache SOLR 是一个基于 Apache Lucene 的高性能开源搜索平台。它不仅继承了 Lucene 强大的全文搜索能力,还通过封装和扩展,提供了企业级的功能,比如分布式搜索(SolrCloud)、RESTful API、动态 Schema 管理等。自 200…...
Docker 搭建 Redis 数据库
Docker 搭建 Redis 数据库 前言一、准备工作二、创建 Redis 容器的目录结构三、启动 Redis 容器1. 通过 redis.conf 配置文件设置密码2. 通过 Docker 命令中的 requirepass 参数设置密码 四、Host 网络模式与 Port 映射模式五、检查 Redis 容器状态六、访问 Redis 服务总结 前言…...
MySQL 连表查询:原理、语法与优化
目录 引言 什么是连表查询? 连表查询的类型 1. 内连接(INNER JOIN) 2. 左连接(LEFT JOIN) 3. 右连接(RIGHT JOIN) 4. 全连接(FULL JOIN) 5. 交叉连接(…...
实战技巧:如何快速提高网站收录的权威性?
快速提高网站收录的权威性是一个系统性的工作,涉及内容质量、网站结构、外部链接、用户体验等多个方面。以下是一些实战技巧,可以帮助你快速提升网站收录的权威性: 一、提升内容质量 原创性: 确保网站内容具备高质量与原创性&a…...
vue语法v-model例子单选题和多选题
<template><!-- 单选框 --><input type"radio" v-model"danxuan" value"a"><label for"a">a</label><input type"radio" v-model"danxuan" value"b"><label fo…...
计算机网络面试知识点总结
目录 1. 计算机网络的基本知识点2. OSI 七层模型3. TCP/IP 四层模型4. TCP 和 UDP4.1 TCP 协议4.2 TCP 流量控制4.3 TCP 拥塞控制4.4 TCP 三次握手4.5 TCP 四次挥手4.6 TCP 粘包问题4.7 TCP Socket交互流程4.8 UDP 协议以及和 TCP 协议的不同 5. HTTP协议5.1 HTTP 请求方法以及…...
JVM生产环境问题定位与解决实战(二):JConsole、VisualVM到MAT的高级应用
生产问题定位指南:几款必备的可视化工具 引言 在上一篇文章中,详细的介绍了JDK自带的一系列命令行工具,,如jps、jmap、jstat、jstack以及jcmd等,这些工具为排查和诊断Java虚拟机(JVM)问题提供…...
c++入门-------命名空间、缺省参数、函数重载
C系列 文章目录 C系列前言一、命名空间二、缺省参数2.1、缺省参数概念2.2、 缺省参数分类2.2.1、全缺省参数2.2.2、半缺省参数 2.3、缺省参数的特点 三、函数重载3.1、函数重载概念3.2、构成函数重载的条件3.2.1、参数类型不同3.2.2、参数个数不同3.2.3、参数类型顺序不同 前言…...
Lua语言入门(自用)
全局与非全局 在lua语言当中没有被local表示的是全局变量 反之则是本地变量(仅仅作用在某个文件,函数,或者代码块) 下面是实例代码和运行结果 --hello.luaA 10;--这样就是全局变量,然后这个编译器如果是大写就是默认的全局变量 local b 3;--这样就是局部变量--reference.…...
大数据开发平台的框架
根据你的需求,以下是从 GitHub 推荐的 10 个可以实现大数据开发平台的项目: 1. Apache Spark Apache Spark 是一个开源的分布式计算框架,适用于大规模数据处理和分析。它提供了强大的数据处理能力,支持实时数据处理、机器学习和…...
X86_64位下的GS寄存器
在 64 位模式下,段机制通常(但不是完全)被禁用,从而创建一个平坦的 64 位线性地址空间。处理器将 CS、DS、ES、SS 的段基地址视为零,从而创建一个与有效地址相等的线性地址。FS 和 GS 段是例外。这些段寄存器ÿ…...
#6【TIP2023】Dif-Fusion
📜 Dif-Fusion: Toward High Color Fidelity in Infrared and Visible Image Fusion With Diffusion Models 🍸 源码:https://github.com/GeoVectorMatrix/Dif-Fusion 🍺 前向扩散过程 前向过程看成是逐步加噪的Markov链,在每一个时间步 t t t ,...
科普:“git“与“github“
Git与GitHub的关系可以理解为:Git是一种软件工具,而GitHub则是一个在线平台,它们是“一家子”。二者的关联最直接体现在你通过Git在GitHub仓库中clone软件包到你的机器中来。 具体来说: 一、Git 定义:Git是一个开源的…...
Python爬虫实战:研究MechanicalSoup库相关技术
一、MechanicalSoup 库概述 1.1 库简介 MechanicalSoup 是一个 Python 库,专为自动化交互网站而设计。它结合了 requests 的 HTTP 请求能力和 BeautifulSoup 的 HTML 解析能力,提供了直观的 API,让我们可以像人类用户一样浏览网页、填写表单和提交请求。 1.2 主要功能特点…...
【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖
在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...
Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...
return this;返回的是谁
一个审批系统的示例来演示责任链模式的实现。假设公司需要处理不同金额的采购申请,不同级别的经理有不同的审批权限: // 抽象处理者:审批者 abstract class Approver {protected Approver successor; // 下一个处理者// 设置下一个处理者pub…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
华为OD机考-机房布局
import java.util.*;public class DemoTest5 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseSystem.out.println(solve(in.nextLine()));}}priv…...
c++第七天 继承与派生2
这一篇文章主要内容是 派生类构造函数与析构函数 在派生类中重写基类成员 以及多继承 第一部分:派生类构造函数与析构函数 当创建一个派生类对象时,基类成员是如何初始化的? 1.当派生类对象创建的时候,基类成员的初始化顺序 …...
GraphQL 实战篇:Apollo Client 配置与缓存
GraphQL 实战篇:Apollo Client 配置与缓存 上一篇:GraphQL 入门篇:基础查询语法 依旧和上一篇的笔记一样,主实操,没啥过多的细节讲解,代码具体在: https://github.com/GoldenaArcher/graphql…...
