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 和两个实现了这个接口的结构体 Dog 和 Cat。

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 类型时,ok 为 true,否则为 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 接口通过简单地声明 Writer 和 Closer 接口,组合了这两个接口的功能。这意味着任何实现了 WriteCloser 接口的类型,也必须实现 Writer 和 Closer 接口定义的所有方法。 

        举例:

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 结构体实现了 Write 和 Close 方法,因此它隐式地实现了 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. Rectangle 和 Circle 结构体都实现了 Shape 接口的 Area 方法。

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

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

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

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

        在Go语言中,错误处理是通过error接口实现的。error是Go的内置接口,只包含一个返回错误描述的Error()方法。如果一个函数可能产生错误,它通常会返回一个error类型的值。如果返回的error为nil,表示没有错误发生;如果不是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. 基础接口实现:Dog、Cat 和 Fish 结构体分别实现了 Animal 接口。

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

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

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

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

main中:

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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…