当前位置: 首页 > news >正文

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主要表现在以下几个方面:

  1. 方法的集合:接口是方法的集合,定义了一个类型需要实现哪些方法,但不关心实现的具体细节。只要一个类型实现了接口中的方法,就被认为实现了这个接口。
  2. 多态实现:接口的核心作用之一是实现多态。在 Go 中,不同类型只要实现了相同的接口方法,就可以通过接口来统一处理,达到灵活的多态性。这使得我们可以编写更加解耦和可扩展的代码。
  3. 空接口 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 提供了三种常用的机制来检测或转换接口的实际类型:

  1. 类型断言(Type Assertion)
  2. 类型开关(Type Switch)
  3. 反射(Reflection)

这三者在 Go 中各有不同的用途,适用于不同的场景。通常情况下,如果你只需要判断一个接口的类型并进行相应处理,类型断言类型开关 是更常见的选择;而 反射 则通常用于更加动态和通用的场景,例如实现框架、库、ORM 等。

下面分别详细介绍这三种机制:

1. 类型断言(Type Assertion)

类型断言用于从接口类型转换回具体类型。它允许我们在运行时检查接口值的动态类型,并进行转换。

语法
value, ok := x.(T)
  • x 是接口类型的变量,T 是你想要转换成的具体类型。
  • 如果 x 存储的值是 T 类型,value 将会是存储的值,而 oktrue
  • 如果 x 存储的值不是 T 类型,value 会是 T 类型的零值,而 okfalse
示例
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)

使用场景

在兼容的类型之间进行显式转换(如 intfloat64)。

用于从接口类型中提取底层的具体类型和值。

操作时机

编译时。

运行时。

适用范围

基本数据类型、自定义类型等。

接口类型(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
}
解释
  • DogCat 都实现了 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!
}
  1. 接口嵌套Worker 接口通过 Animal 接口嵌套了 Speak 方法,这意味着 Worker 接口需要实现 SpeakWork 方法。

  2. Dog 类型实现接口Dog 类型实现了 SpeakWork 方法,满足了 Worker 接口的要求。

  3. 接口引用:在 main 函数中,wWorker 类型的接口变量,它引用了 Dog 类型的对象。由于 Dog 类型实现了 SpeakWork 方法,所以可以调用 w.Speak()w.Work()

总结
  • Go 中的接口:接口是一组方法签名的集合,Go 语言通过接口实现了多态。
  • 隐式实现:Go 中不需要显式声明类型实现接口,任何实现了接口方法的类型都会自动实现该接口。
  • 空接口interface{} 可以存储任何类型的值,类似于其他语言中的 Object 类型。
  • 类型断言:允许从接口类型转换回具体类型,提供灵活的运行时类型检查。
  • 接口与多态:通过接口,Go 实现了动态多态,允许不同类型通过统一的接口调用各自的行为。

接口是 Go 语言的核心特性之一,它使得 Go 在保持简洁和灵活性的同时,支持面向对象的编程风格。

历史文章

MySQL数据库

MySQL数据库

Redis

Redis数据库笔记合集

Golang
  1. Golang笔记——语言基础知识
  2. Golang笔记——切片与数组
  3. Golang笔记——hashmap
  4. Golang笔记——rune和byte
  5. 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:感知-规划一体化 核心思想:首次提出将感知任务(如目标检测、车道线识别、轨迹预测)与规划任务集成到统一的端到端框架中&#xff…...

第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的高级应用

生产问题定位指南&#xff1a;几款必备的可视化工具 引言 在上一篇文章中&#xff0c;详细的介绍了JDK自带的一系列命令行工具&#xff0c;&#xff0c;如jps、jmap、jstat、jstack以及jcmd等&#xff0c;这些工具为排查和诊断Java虚拟机&#xff08;JVM&#xff09;问题提供…...

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.…...

大数据开发平台的框架

根据你的需求&#xff0c;以下是从 GitHub 推荐的 10 个可以实现大数据开发平台的项目&#xff1a; 1. Apache Spark Apache Spark 是一个开源的分布式计算框架&#xff0c;适用于大规模数据处理和分析。它提供了强大的数据处理能力&#xff0c;支持实时数据处理、机器学习和…...

X86_64位下的GS寄存器

在 64 位模式下&#xff0c;段机制通常&#xff08;但不是完全&#xff09;被禁用&#xff0c;从而创建一个平坦的 64 位线性地址空间。处理器将 CS、DS、ES、SS 的段基地址视为零&#xff0c;从而创建一个与有效地址相等的线性地址。FS 和 GS 段是例外。这些段寄存器&#xff…...

#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的关系可以理解为&#xff1a;Git是一种软件工具&#xff0c;而GitHub则是一个在线平台&#xff0c;它们是“一家子”。二者的关联最直接体现在你通过Git在GitHub仓库中clone软件包到你的机器中来。 具体来说&#xff1a; 一、Git 定义&#xff1a;Git是一个开源的…...

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…...

linux之kylin系统nginx的安装

一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源&#xff08;HTML/CSS/图片等&#xff09;&#xff0c;响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址&#xff0c;提高安全性 3.负载均衡服务器 支持多种策略分发流量…...

渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止

<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet&#xff1a; https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...

【解密LSTM、GRU如何解决传统RNN梯度消失问题】

解密LSTM与GRU&#xff1a;如何让RNN变得更聪明&#xff1f; 在深度学习的世界里&#xff0c;循环神经网络&#xff08;RNN&#xff09;以其卓越的序列数据处理能力广泛应用于自然语言处理、时间序列预测等领域。然而&#xff0c;传统RNN存在的一个严重问题——梯度消失&#…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

现代密码学 | 椭圆曲线密码学—附py代码

Elliptic Curve Cryptography 椭圆曲线密码学&#xff08;ECC&#xff09;是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础&#xff0c;例如椭圆曲线数字签…...

ardupilot 开发环境eclipse 中import 缺少C++

目录 文章目录 目录摘要1.修复过程摘要 本节主要解决ardupilot 开发环境eclipse 中import 缺少C++,无法导入ardupilot代码,会引起查看不方便的问题。如下图所示 1.修复过程 0.安装ubuntu 软件中自带的eclipse 1.打开eclipse—Help—install new software 2.在 Work with中…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

CVPR2025重磅突破:AnomalyAny框架实现单样本生成逼真异常数据,破解视觉检测瓶颈!

本文介绍了一种名为AnomalyAny的创新框架&#xff0c;该方法利用Stable Diffusion的强大生成能力&#xff0c;仅需单个正常样本和文本描述&#xff0c;即可生成逼真且多样化的异常样本&#xff0c;有效解决了视觉异常检测中异常样本稀缺的难题&#xff0c;为工业质检、医疗影像…...

抽象类和接口(全)

一、抽象类 1.概念&#xff1a;如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象&#xff0c;这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法&#xff0c;包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中&#xff0c;⼀个类如果被 abs…...