GO语言基础笔记(六):接口interface

目录

1. 接口(Interface)

2. 接口的基本使用方法

3. 接口的注意事项

4. 接口使用的技巧 

代码示例


1. 接口(Interface)

接口是定义了一组方法签名的类型,它规定了对象的行为。在Go中,接口是隐式实现的,即如果一个类型实现了接口所有的方法,则它就实现了这个接口。

接口定义示例:

        这个Reader接口包含了一个Read方法

type Reader interface {Read(p []byte) (n int, err error)
}

接口实现示例:

type File struct {// ...
}func (f *File) Read(p []byte) (n int, err error) {// 实现细节...
}

  File类型通过实现Read方法隐式地实现了Reader接口。

2. 接口的基本使用方法

        接口在Go中是隐式实现的。这意味着如果某个类型为接口中所有方法提供了实现,则该类型实现了该接口。

type Shape interface {Area() float64Perimeter() float64
}

type Rectangle struct {Length, Width float64
}func (r Rectangle) Area() float64 { //Rectangle类型隐式实现了Shape接口Area() return r.Length * r.Width
}func (r Rectangle) Perimeter() float64 { // Rectangle类型隐式实现了Shape接口Perimeter() return 2 * (r.Length + r.Width)
}// Rectangle类型隐式实现了Shape接口

        这种隐式实现的好处是代码的解耦。Rectangle类型可以在完全不知道Shape接口的存在的情况下被定义和实现。只要它的方法符合某个接口的要求,它就自动实现了那个接口。这种方式使得不同的包可以非常灵活地互相协作,只要它们的接口相匹配。

        这种设计哲学是Go语言中非常重要的特性之一,它鼓励了接口的简洁性和高度抽象,同时增加了代码之间的解耦性。如果您对这部分内容还有疑问,或需要更多示例来理解,欢迎随时提问。继续学习和探索Go语言,您会发现它的设计充满智慧和实用性。加油!

3. 接口的注意事项

  • 隐式实现:接口在Go中是通过类型的方法实现的,而不是通过显式声明。
  • 空接口:空接口interface{}可以保存任何类型的值,因为所有类型都至少实现了零个方法。
  • 类型断言:可以使用类型断言来检查接口值是否包含特定的类型。
  • 接口值:接口类型的变量可以持有任何实现该接口的类型的值。

        假设我们有一个接口 Animal 和两个实现了这个接口的结构体 DogCat

type Animal interface {Speak() string
}type Dog struct{}func (d Dog) Speak() string {return "Woof!"
}type Cat struct{}func (c Cat) Speak() string {return "Meow!"
}

        现在,我们创建一个 Animal 类型的切片,里面既有 Dog 类型的实例,也有 Cat 类型的实例。 

animals := []Animal{Dog{}, Cat{}}

        然后,我们使用类型断言来检查这些动物的具体类型。

for _, animal := range animals {switch a := animal.(type) {case Dog:fmt.Println("This is a Dog and it says:", a.Speak())case Cat:fmt.Println("This is a Cat and it says:", a.Speak())default:fmt.Println("Unknown animal")}
}

        类型断言也可以返回一个单一的值,这在你确定接口值的类型时非常有用。

if dog, ok := animal.(Dog); ok {fmt.Println("This is a Dog and it says:", dog.Speak())
}

        在这里,ok 是一个布尔值,当 animal 确实是 Dog 类型时,oktrue,否则为 false

        类型断言是Go语言中处理接口和类型转换的强大工具,理解并熟练使用它将在很多场合帮助你写出更灵活和安全的代码。继续探索Go语言的世界,您会发现它的强大和优雅。加油!

4. 接口使用的技巧 

接口组合:接口可以通过其他接口组合而成,使得代码更加模块化和灵活。

type ReaderWriter interface {ReaderWriter
}

        假设我们有两个基本接口,分别定义了不同的行为: 

type Writer interface {Write(p []byte) (n int, err error)
}type Closer interface {Close() error
}

        这里,Writer 接口定义了一个 Write 方法,用于写入数据,而 Closer 接口定义了一个 Close 方法,用于关闭资源。

        现在,如果我们想要一个同时包含写入和关闭功能的接口,我们可以通过组合这两个接口来创建一个新的接口:

type WriteCloser interface {WriterCloser
}

  WriteCloser 接口通过简单地声明 WriterCloser 接口,组合了这两个接口的功能。这意味着任何实现了 WriteCloser 接口的类型,也必须实现 WriterCloser 接口定义的所有方法。 

        举例:

type File struct {// 文件相关的字段
}func (f *File) Write(p []byte) (n int, err error) {// 实现写入逻辑return len(p), nil
}func (f *File) Close() error {// 实现关闭逻辑return nil
}

        在这个例子中,File 结构体实现了 WriteClose 方法,因此它隐式地实现了 WriteCloser 接口。

类型断言:用于从接口类型检索底层具体值。 

var i interface{} = "hello"
s := i.(string)

类型开关:Type switch用于判断接口值的类型。 

switch v := i.(type) {
case int:// v是一个int
case string:// v是一个string
}

接口作为函数参数:使用接口作为函数参数可以使函数更加通用。

        首先,定义一个接口和几个实现了该接口的结构体:

// Shape 接口定义了一个计算面积的方法
type Shape interface {Area() float64
}// Rectangle 结构体实现了 Shape 接口
type Rectangle struct {Width, Height float64
}func (r Rectangle) Area() float64 {return r.Width * r.Height
}// Circle 结构体实现了 Shape 接口
type Circle struct {Radius float64
}func (c Circle) Area() float64 {return math.Pi * c.Radius * c.Radius
}

        接下来,定义一个函数,其参数是一个实现了 Shape 接口的类型: 

// DescribeShape 接受 Shape 接口类型的参数,并打印出形状的面积
func DescribeShape(s Shape) {fmt.Printf("Shape Area: %f\n", s.Area())
}

        最后,在 main 函数中使用这个函数: 

func main() {r := Rectangle{Width: 3, Height: 4}c := Circle{Radius: 5}// 使用不同的形状调用 DescribeShapeDescribeShape(r)DescribeShape(c)
}

在这段代码中:

  1. 我们定义了一个 Shape 接口,它包含一个方法 Area,用于计算面积。

  2. RectangleCircle 结构体都实现了 Shape 接口的 Area 方法。

  3. DescribeShape 函数接受一个 Shape 接口类型的参数。这意味着任何实现了 Shape 接口的类型都可以作为参数传递给这个函数。

  4. main 函数中,我们创建了 RectangleCircle 类型的实例,并将它们传递给 DescribeShape 函数。由于这两个类型都实现了 Shape 接口,它们可以被用作 DescribeShape 函数的参数。

        通过这种方式,DescribeShape 函数能够处理任何实现了 Shape 接口的类型,使得函数具有很高的灵活性和通用性。这是接口在Go语言中的强大应用之一,它极大地促进了代码的抽象和解耦。继续探索Go语言,你会发现更多有趣和有用的特性。加油!

错误处理:在Go中,error是一个内置接口,用于处理错误情况。

        在Go语言中,错误处理是通过error接口实现的。error是Go的内置接口,只包含一个返回错误描述的Error()方法。如果一个函数可能产生错误,它通常会返回一个error类型的值。如果返回的errornil,表示没有错误发生;如果不是nil,则表示发生了错误。

        首先,定义一个可能产生错误的函数:

// Divide 两个整数相除,返回结果和可能发生的错误
func Divide(a, b int) (result float64, err error) {if b == 0 {// 使用 fmt.Errorf 创建一个新的错误对象return 0, fmt.Errorf("cannot divide by zero")}// 正常情况下返回结果和 nil(表示没有错误)return float64(a) / float64(b), nil
}

        接下来,在main函数中调用这个函数并处理可能出现的错误: 

func main() {// 正确的除法操作result, err := Divide(10, 2)if err != nil {// 如果有错误发生,打印错误并退出log.Fatalf("An error occurred: %v", err)}fmt.Printf("10 / 2 = %f\n", result)// 错误的除法操作(除数为0)result, err = Divide(10, 0)if err != nil {// 如果有错误发生,打印错误并退出log.Fatalf("An error occurred: %v", err)}fmt.Printf("10 / 0 = %f\n", result)
}

在这段代码中:

  1. Divide函数接受两个整数参数,并返回一个浮点数结果和一个error对象。

  2. 如果第二个参数(除数)为0,则Divide函数会返回一个错误,使用fmt.Errorf来创建这个错误对象。

  3. main函数中,我们首先尝试一个有效的除法操作,然后尝试一个除数为0的除法操作。

  4. 每次调用Divide后,我们检查返回的error对象。如果它不是nil,表示有错误发生,我们打印错误信息并退出程序。

        通过这种方式,Go语言中的错误处理非常清晰和直观。error接口提供了一种简单而一致的处理错误的方式。在实际开发中合理使用错误处理,可以使你的程序更加健壮和可维护。继续探索Go语言的功能,你会发现它为错误处理提供了很好的支持。加油!

实现检查:可使用空白标识符来检查类型是否实现了接口。

        假设我们有一个接口和一个结构体,我们想要确保这个结构体实现了该接口。首先,定义一个接口:

// Speaker 接口定义了一个Speak方法
type Speaker interface {Speak() string
}

        接着,定义一个可能实现了这个接口的结构体: 

// Dog 结构体代表了一个狗的类型
type Dog struct{}// Dog类型实现了Speaker接口的Speak方法
func (d Dog) Speak() string {return "Woof!"
}

        现在,我们使用空白标识符来检查Dog类型是否实现了Speaker接口:

// 编译时的接口实现检查
var _ Speaker = Dog{}

在这段代码中:

  • var _ Speaker = Dog{} 这行代码是实现检查的关键。它尝试将一个Dog类型的实例赋值给一个Speaker接口类型的变量(使用空白标识符_作为变量名,表示我们不会使用这个变量)。

  • 如果Dog没有实现Speaker接口,这行代码将导致编译错误,因为Dog{}不能赋值给Speaker类型的变量。

  • 如果Dog正确实现了Speaker接口,这行代码不会有任何运行时效果,但它确保了类型正确实现了接口。

        这种方法常用于库和框架的开发中,确保类型正确实现了必要的接口,从而在编译时而非运行时捕获错误,提高代码质量。

        通过这样的机制,Go语言在编译阶段就可以强制执行接口的实现,这是一种非常有用的特性,有助于提早发现并修复潜在的错误。

代码示例

        下面是一个使用Go语言接口的示例,它展示了如何使用接口来创建一个简单的动态多态系统。这个例子中,我们将创建一个动物园模拟器,其中包含不同类型的动物,每种动物都有自己独特的叫声和行为。

package mainimport ("fmt""math"
)// Animal 接口定义了所有动物共有的行为
type Animal interface {Speak() stringMove() string
}// Dog 结构体表示狗
type Dog struct{}// Dog的叫声
func (d Dog) Speak() string {return "Woof!"
}// Dog的移动方式
func (d Dog) Move() string {return "Run"
}// Cat 结构体表示猫
type Cat struct{}// Cat的叫声
func (c Cat) Speak() string {return "Meow"
}// Cat的移动方式
func (c Cat) Move() string {return "Jump"
}// Fish 结构体表示鱼
type Fish struct{}// Fish的叫声
func (f Fish) Speak() string {return "..."
}// Fish的移动方式
func (f Fish) Move() string {return "Swim"
}// 演示动物园的功能
func main() {animals := []Animal{Dog{}, Cat{}, Fish{}}for _, animal := range animals {fmt.Printf("This animal says '%s' and moves by '%s'.\n", animal.Speak(), animal.Move())// 使用类型断言检查是否为Cat类型if cat, ok := animal.(Cat); ok {fmt.Printf("This is a Cat: %v\n", cat)}}// 接口组合的演示var wc WriterCloser = &MyWriterCloser{}wc.Write([]byte("Hello, Go!"))wc.Close()
}// Writer 接口定义了写操作
type Writer interface {Write(p []byte) (n int, err error)
}// Closer 接口定义了关闭操作
type Closer interface {Close() error
}// WriterCloser 接口组合了Writer和Closer
type WriterCloser interface {WriterCloser
}// MyWriterCloser 结构体实现了WriterCloser接口
type MyWriterCloser struct{}// 实现Writer接口的Write方法
func (mwc *MyWriterCloser) Write(p []byte) (n int, err error) {fmt.Println("Writing:", string(p))return len(p), nil
}// 实现Closer接口的Close方法
func (mwc *MyWriterCloser) Close() error {fmt.Println("Closing")return nil
}// 使用空白标识符进行接口实现检查
var _ WriterCloser = &MyWriterCloser{}func main() {animals := []Animal{Dog{}, Cat{}, Fish{}}// 遍历动物并打印它们的行为for _, animal := range animals {fmt.Printf("This animal says '%s' and moves by '%s'.\n", animal.Speak(), animal.Move())// 类型断言:检查动物类型switch a := animal.(type) {case Dog:fmt.Println("This is a Dog.")case Cat:fmt.Println("This is a Cat.")case Fish:fmt.Println("This is a Fish.")default:fmt.Println("Unknown animal type.")}}// 接口组合:使用WriterCloservar wc WriterCloser = &MyWriterCloser{}wc.Write([]byte("Hello, Go!"))wc.Close()// 接口实现检查fmt.Println("MyWriterCloser successfully implements WriterCloser.")
}

在这个示例中,我们演示了以下几点:

  1. 基础接口实现DogCatFish 结构体分别实现了 Animal 接口。

  2. 类型断言:在 main 函数中,我们对 animals 切片中的每个元素使用了类型断言来检查是否为 Cat 类型。

  3. 接口组合:定义了一个 WriterCloser 接口,它组合了 WriterCloser 接口。

  4. 实现组合接口MyWriterCloser 结构体实现了 WriterCloser 接口。

  5. 接口实现检查:使用空白标识符 _ 来检查 MyWriterCloser 是否实现了 WriterCloser 接口。

main中:

  1. 类型断言的应用:使用 switch 语句和类型断言来确定每个动物的具体类型,并打印相应的信息。

  2. 接口组合的应用:创建了 WriterCloser 接口的一个实例,并调用了它的 WriteClose 方法。

  3. 接口实现检查:确认 MyWriterCloser 是否成功实现了 WriterCloser 接口,并打印一条确认信息。

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

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

相关文章

【ArcGIS微课1000例】0083:地震灾害图件制作之土壤类型分布图

本文基于1:400万矢量土壤图,制作甘肃积石山6.2级地震100km范围内土壤类型分布图。 文章目录 一、土壤分布图预览二、数据集来源及简介三、土壤分布图制作一、土壤分布图预览 二、数据集来源及简介 1. 数据来源 数据集为1:400万中国土壤图,1:400万中国土壤图(2000)由中国科…

Pytorch整体框架学习

12.28 Learn Pytorch 一、神经网络 二、pytorch的整体框架 1.torch (1).Tensor概念 张量 ,最基础的运算单位 ,一个多维矩阵,一个可以运行在gpu上的多维数据 (2).Tensor的创建 torch.FloatTensor(2,3) / torch.FloatTensor([2,3,4,5])to…

每日力扣算法题(简单篇)

455.分发饼干 原题: 假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。 对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干…

编程新手IDE

身为一个前端开发者,我深知一个好的开发环境对于编程体验的重要性。对于新手来说,选择一个合适的IDE(集成开发环境)更是至关重要。一个好的IDE可以提高编程效率,减少错误,让新手更专注于学习编程本身。 今…

大创项目推荐 深度学习交通车辆流量分析 - 目标检测与跟踪 - python opencv

文章目录 0 前言1 课题背景2 实现效果3 DeepSORT车辆跟踪3.1 Deep SORT多目标跟踪算法3.2 算法流程 4 YOLOV5算法4.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 最后 0 前言 🔥 优质竞赛项目系列,今天要分享的是 🚩 *…

模式识别与机器学习-集成学习

集成学习 集成学习思想过拟合与欠拟合判断方法 K折交叉验证BootstrapBagging随机森林的特点和工作原理: BoostingAdaBoost工作原理:AdaBoost的特点和优点:AdaBoost的缺点: Gradient Boosting工作原理:Gradient Boostin…

node: /lib64/libm.so.6: version `GLIBC_2.27‘ not found

node: /lib64/libm.so.6: version GLIBC_2.27‘ not found 1.背景说明2.原因3.解决方法4.打包镜像5. 参考 1.背景说明 为了适配vue3 ,发布前端项目的jenkins分发镜像必须升级node 版本,如下镜像脚本 FROM kubesphere/builder-nodejs:v3.2.0 RUN npm ca…

android 13.0 Launcher3长按app弹窗设置为圆角背景功能实现一

1.前言 在13.0的系统ROM定制化开发中,在进行一些Launcher3的定制化开发中,在使用app的弹窗的功能时,会弹出应用信息和微件之类的内容,所以在定制需求中,需要默认设置为圆角背景,接下来就来分析下相关功能的实现 如图: 2.Launcher3长按app弹窗设置为圆角背景功能实现的核…

【MYSQL】-函数

💖作者:小树苗渴望变成参天大树🎈 🎉作者宣言:认真写好每一篇博客💤 🎊作者gitee:gitee✨ 💞作者专栏:C语言,数据结构初阶,Linux,C 动态规划算法🎄 如 果 你 …

AcWing 1076. 迷宫问题(最短路模型)

题目链接 活动 - AcWing本课程系统讲解常用算法与数据结构的应用方式与技巧。https://www.acwing.com/problem/content/description/1078/ 来源 《信息学奥赛一本通》, kuangbin专题 , POJ3984 代码 #include <cstring> #include <iostream> #include <alg…

Servlet的自动加载、ServletConfig对象、ServletContext对象

一、 Servlet的自动加载 默认情况下&#xff0c;第一次访问servlet的时候&#xff0c;创建servlet对象。如果servlet构造函数里面的代码或者init方法里面的代码比较多&#xff0c;就会导致用户第一次访问servlet的时候比较慢。这个时候&#xff0c;我们可以改变servlet对象的创…

【网络安全常用术语解读】SCAP详解

本文主要介绍什么是SCAP&#xff0c;SCAP的产生背景是怎样的&#xff0c;SCAP有什么用途&#xff0c;有哪些组件&#xff0c;各个组件的用途是什么&#xff1f; SCAP产生背景 由于计算机和网络技术的快速发展&#xff0c;越来越多的软件和系统被应用到企业和机构中&#xff0c…

迭代归并:归并排序非递归实现解析

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《数据结构&算法》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! &#x1f4cb; 前言 归并排序的思想上我们已经全部介绍完了&#xff0c;但是同时也面临和快速排序一样的问题那就是递…

通信原理课设(gec6818) 007:语音识别

目录 1、去科大讯飞官网下载对应的sdk 2、科大讯飞文件夹的意思 3、配置ARM的录音环境 4、编程实现语音识别 我们的需求是将一个语音文件从客户端传到服务器&#xff0c;因此我们最好是选用tcp 现在市面上面常用的语音识别解决方案为&#xff1a;科大讯飞c和百度c 离…

龙芯3A5000上安装使用QQ

原文链接&#xff1a;龙芯3A5000上安装使用QQ hello&#xff0c;大家好啊&#xff01;今天我要给大家带来的是在龙芯3A5000处理器上安装使用QQ的文章。近期&#xff0c;腾讯发布了最新版本的QQ&#xff0c;值得一提的是&#xff0c;这一版本增加了对Linux系统下龙芯架构的支持。…

KG+LLM(一)KnowGPT: Black-Box Knowledge Injection for Large Language Models

论文链接&#xff1a;2023.12-https://arxiv.org/pdf/2312.06185.pdf 1.Background & Motivation 目前生成式的语言模型&#xff0c;如ChatGPT等在通用领域获得了巨大的成功&#xff0c;但在专业领域&#xff0c;由于缺乏相关事实性知识&#xff0c;LLM往往会产生不准确的…

项目记录:利用Redis实现缓存以提升查询效率

一、概述 当我们查询所有数据时&#xff0c;如果缓存中没有&#xff0c;则去数据库查询&#xff0c;如果有&#xff0c;直接查缓存的数据就行。注意定期更新缓存数据。 二、主体代码 private static final String ROOM_SCHEDULES_HASH "RoomSchedules";Overridepu…

pytorch 多卡训练 accelerate gloo

目录 accelerate 多卡训练 Windows例子 gloo 多卡训练 accelerate 多卡训练 Windows例子 import torch from torch.nn.parallel import DistributedDataParallel as DDP from torch.utils.data import DataLoader, RandomSampler from accelerate import Accelerator# 模拟数…

HTML---JavaScript基础

文章目录 目录 文章目录 本章目标 一.JavaScript基础 概述 特点 JavaScript 基本机构 语法 网页中引用JavaScript的方式 二. JavaScript核心语法 变量 ​编辑 数据类型 数组 练习 本章目标 掌握JavaScript的组成掌握JavaScript的基本语法会定义和使用函数会使用工具进行…

引领手游技术潮流:武汉灰京文化的卓越技术创新与市场推广支持

在数字娱乐领域&#xff0c;手游行业正蓬勃发展&#xff0c;为数以亿计的玩家提供了丰富的娱乐选择。武汉灰京文化&#xff0c;作为该领域的佼佼者&#xff0c;以其强大的技术创新和全面的市场推广支持&#xff0c;为合作伙伴的成功铺平了道路&#xff0c;不仅提升了游戏质量&a…