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

Go 1.19.4 接口-Day 10

1. 接口

1.1 基本介绍

接口中到底应该定义些什么?
在Go语言中,接口是声明函数的集合,但只有函数签名,没有具体的功能。
属于是面向对象中,行为的约束,面向对象中的类有自己的属性(可以当成数据成员或字段)、方法(可以当成函数,函数有自己的操作或行为),如下代码:

type 接口名称 interface {dog() // 方法1签名cat() // 方法2签名方法1 (参数列表1) 返回值列表1方法2 (参数列表2) 返回值列表2
}

上面这个接口A,要求实现者,必须实现方法1和方法2(就是命名函数时,只能用接口中的函数名命名)。
也就是说,如果有谁声称实现了某某接口,那就必须实现该接口中的所有方法。

1.2 使用接口注意事项

  • 接口命名习惯在接口名后面加上er后缀。
  • 参数列表、返回值列表参数名可以不写。
  • 如果要在包外使用接口,接口名应该首字母大写,方法要在包外使用,方法名首字母也要大写。
  • 接口中的方法应该设计合理,不要太多,甚至越少越好。

2. 接口实现

如果一个结构体实现了一个接口声明的所有方法,就说结构体实现了该接口。
一个结构体可以实现多个接口。

2.1 实现单个接口

package mainimport "fmt"// 定义一个"运动"接口
type Sport interface {// Go倾向小接口,只有一个方法都行run()  // 跑步jump() // 跳跃
}// 该接口由"人"来实现
type Person struct {name stringage  int
}// 实现接口
///实现接口方法1
func (*Person) run() {fmt.Println("跑步")
}///实现接口方法2
func (*Person) jump() {fmt.Println("跳跃")
}func main() {p1 := new(Person) // 创建一个新的指针实例,减少数据拷贝次数p1.jump()p1.run()
}
==============调试结果==============
跳跃
跑步

再来看一个特殊示例

package mainimport "fmt"type Sport interface {run()  // 跑步jump() // 跳跃
}type Person struct {name stringage  int
}func (*Person) run() {fmt.Println("跑步")
}func (*Person) jump() {fmt.Println("跳跃")
}// 我这里新加了一个成员方法,请问Person结构体实现了Sport接口吗?
// 当然实现了,上面两个成员方法已经实现了Sport接口,我当然可以继续定义Person结构体的其他方法。
func (t *Person) swim() {fmt.Println("游泳")
}func main() {p1 := new(Person)p1.jump()p1.run()p1.swim()
}
==============调试结果==============
跳跃
跑步
游泳

2.1.1 把接口类型赋值给变量

package mainimport "fmt"type Sport interface {run()jump()
}type Person struct {name stringage  int
}func (*Person) run() {fmt.Println("跑步")
}func (*Person) jump() {fmt.Println("跳跃")
}func (t *Person) swim() {fmt.Println("游泳")
}func main() {p1 := new(Person)p1.jump()p1.run()p1.swim()fmt.Println("-------------------")var a Sport = p1 // 把接口类型赋值给变量,该变量就是个接口类型的变量了fmt.Println(a)a.jump() // 可以直接调用接口中的方法a.run()
}
==============调试结果==============
跳跃
跑步
游泳
-------------------
&{ 0}
跳跃
跑步

3. 接口嵌入(组合)

除了结构体可以嵌套,接口也可以。接口嵌套组合成了新接口。

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

这样写的好处,就是如果需要同时调用Reader和Closer,直接调用ReadCloser就行了。

4. 空接口

4.1 什么是空接口

在 Go 语言中,空接口(interface{})是一个没有方法的接口。这意味着任何类型都可以实现空接口(或者说空接口可以匹配任意类型的数据),因为它们不需要满足任何方法的要求。
空接口可以存储任何类型的值,这使得它在需要存储未知类型数据时非常有用。

4.2 定义空接口

4.2.1 基本定义

func main() {var b interface{} // 空接口类型,注意是空接口类型,这部分interface{}表示数据类型var c any // 这样也行,any是interface{}的别名(鼠标移到any上能看到)
}

4.2.2 空接口和任意数据类型组合

func main() {var a = 500var b interface{} // 空接口,b的类型是接口类型,但是个空接口// var b any // 或者这样声明,更好理解,any表示任意数据类型// 为什么b能等于a?因为interface{}是空接口,里面没有任何方法。// 换句话说,不管什么类型,都能实现空接口。b = afmt.Printf("b的类型:%T\nb的值:%+[1]v\n", b)fmt.Println("-----------------------------------")var c = "abc"b = cfmt.Printf("b的类型:%T\nb的值:%+[1]v\n", b)
}
================调试结果================
b的类型:int
b的值:500
-----------------------------------
b的类型:string
b的值:abc

4.3 为什么要用空接口

比如我有这样一个需求:我需要一个容器,该容器能存储任意类型的数据,并且能够混装,注意是能混装!
这咋整呢?用结构体吗?不行,结构体虽然能混装不同的数据类型,但它有个前提,必须要有明确的字段。
所以这种情况下只有空接口interface{}是最合适的。

var d = []any{1, 2.1, true, "abc"}
// []interface{},表示数据类型,后面的{}表示元素字面量定义
var e = []interface{}{1, 2.1, true, "abc"}
fmt.Printf("d的类型:%T|d的值:%+[1]v\n", d)
fmt.Printf("e的类型:%T|e的值:%+[1]v\n", e)
================调试结果================
d的类型:[]interface {}|d的值:[1 2.1 true abc] // 返回值为任意数据类型的切片
e的类型:[]interface {}|e的值:[1 2.1 true abc]

5. 接口类型断言

5.1 基本介绍

在 Go 语言中,当你有一个接口变量时,你可以通过 类型断言 来检查它实际存储的类型,注意只能配合接口使用。
类型断言的基本语法是 变量.(数据类型)。

5.2 示例

5.2.1 基本使用

var a = 500
var b interface{} = a// v, ok := b.(int) 含义:把b接口中存储的数据当成int,可以吗?
// 可以:ok返回true,v返回对应的值
// 不可以:ok返回false,v返回对应数据类型的默认值(int:0,str: 空串)
v, ok := b.(int)
fmt.Printf("v=%v ok=%v\n", v, ok)v1, ok1 := b.(string)
fmt.Printf("v=%v ok=%v\n", v1, ok1)
================调试结果================
v=500 ok=true
v= ok=false // 注意这里的v是空串

5.2.2 结合if判断

string类型,断言失败会返回空串,但万一默认就是空串呢?所以这里最好结合if一起使用,判断ok的值来判断类型断言是否成功,如下代码:

var a = 500
var b interface{} = aif v, ok := b.(string); ok {fmt.Printf("断言成功,v的类型为:%T 值为:%[1]v", v)
} else {fmt.Printf("断言失败,v的类型为:%T 值为:%[1]v", v)
}
================调试结果================
断言失败,v的类型为:string 值为:

5.3 type-switch

当需要判断多个原始数据类型时,写if的话,需要写很长的代码,这里可以使用type-switch来替代if,更加简洁。
注意:type-switch只能配合接口类型断言使用。

var a = 500
var b interface{} = a// b.(type)的意思,是取b接口中数据的类型
switch b.(type) { // 这个b.(type)可以用变量接住,值会赋值给该变量
case int:fmt.Println("int,值=",b)
case string:fmt.Println("string")
case bool:fmt.Println("bool")
case nil: // 在判断接口或指针类型时,最好加上nil判断,防止出现空接口或空指针fmt.Println("nil 空接口")
default:fmt.Println("其他")
}
================调试结果================
int,值= 500

6. 接口输出格式化

6.1 普通方式格式化

先看一段代码:

package mainimport ("fmt"
)type Sport interface {run()jump()
}type Person struct {name stringage  int
}func (*Person) run() {fmt.Println("跑步")
}func (*Person) jump() {fmt.Println("跳跃")
}func (t *Person) swim() {fmt.Println("游泳")
}func main() {var p = new(Person)fmt.Printf("%+v\n", p)
}
================调试结果================
&{name: age:0}

可以看到上述代码默认输出格式,看起来不太美观,可以如下优化一下:

package mainimport ("fmt"
)type Sport interface {run()jump()
}type Person struct {name stringage  int
}func (*Person) run() {fmt.Println("跑步")
}func (*Person) jump() {fmt.Println("跳跃")
}func (t *Person) swim() {fmt.Println("游泳")
}func Print(p *Person) string {return fmt.Sprintf("我叫%s,我的年龄是%d", p.name, p.age)
}func NewPerson(name string, age int) *Person {return &Person{name, age}
}func main() {var p = NewPerson("Tom", 21)fmt.Println(Print(p))
}
================调试结果================
我叫Tom,我的年龄是21

6.2 方法格式化

package mainimport ("fmt"
)type Sport interface {run()jump()
}type Person struct {name stringage  int
}func (*Person) run() {fmt.Println("跑步")
}func (*Person) jump() {fmt.Println("跳跃")
}func (t *Person) swim() {fmt.Println("游泳")
}func (p *Person) String() string {return fmt.Sprintf("我叫%s,我的年龄是%d", p.name, p.age)
}func NewPerson(name string, age int) *Person {return &Person{name, age}
}func main() {var p = NewPerson("Tom", 21)fmt.Printf("%+v\n", p)fmt.Printf("%v\n", p)fmt.Println(p)fmt.Print(p)
}
================调试结果================
我叫Tom,我的年龄是21
我叫Tom,我的年龄是21
我叫Tom,我的年龄是21
我叫Tom,我的年龄是21

相关文章:

Go 1.19.4 接口-Day 10

1. 接口 1.1 基本介绍 接口中到底应该定义些什么? 在Go语言中,接口是声明函数的集合,但只有函数签名,没有具体的功能。 属于是面向对象中,行为的约束,面向对象中的类有自己的属性(可以当成数据…...

智能编程新纪元:腾讯AI代码助手的高效编程体验

智能编程新纪元:腾讯AI代码助手的高效编程体验 智能编程新纪元:腾讯AI代码助手的高效编程体验引言一、配置开发环境二、AI助手实现高效编程2.1 AI助手自动补全2.2 AI助手实现编程思维2.3 AI助手高效注解2.4 AI助手打破语言壁垒 三、帮助和提升四、优化和…...

使用snap安装docker配置阿里云镜像加速

使用snap安装docker非常的简单,一条命令即可 snap install docker 但是通过这个命令安装的docker, 配置阿里云镜像跟常规安装的配置起来不太一样, 下面讲一下配置流程 修改docker配置文件/var/snap/docker/current/config/daemon.json 这个文件应该是已经创建好…...

安全编程的代码示例

一、python代码示例 一个安全编程的示例是对输入进行严格的验证和过滤。比如,当用户在网页上输入用户名和密码时,应该对这些输入进行验证,防止恶意用户输入恶意代码或进行 SQL 注入等攻击。下面是一个简单的示例代码: import…...

【实现100个unity特效之15】最简单的方法使用shader graphs实现2d非像素和像素树叶草的随风摇摆效果

文章目录 前言非像素树叶草飘动效果新建材质效果像素树叶草飘动效果参考完结 前言 本文只是实现一个简单版本的2d树叶草随风摇摆的效果,如果你想要实现更加复杂的效果,包括2d互动草,你可以参考我之前的文章: 【推荐100个unity插件…...

Vue3+TS+element plus实现一个简单列表页面

期望完成效果 1.创建一个api api内容: 根据接口: 修改 url 和 函数的参数 以及 params里的内容 import { request } from "/utils/service" /** 查 */ export function getDyLogDataApi(page: any, limit: any, campaign_id: any, adgroup_id…...

Go语言中gin+gorm开发前端端分离博客时遇到的问题,gorm执行查询时如何选中特定字段?

代码获取 本篇文章的代码放在了Github上,可以免费获取。 https://github.com/zhangdapeng520/zdpgo_gin_examples 概述 在查询用户信息的时候,由于密码这个字段比较敏感,需要进行处理,不要返回给前端。 我一开始的解决方案是直…...

计算机网络11——数据库语法2

1、变量 (1)局部变量 函数里面定义的,变量名 类型 (2)会话变量 本次连接会话有效,不需要定义声明,直接使用,@变量名 类型 set @x=10; select @x;(3)系统变量 又叫全局变量,只有root变量才能使用,一直有效。因为全局变量影响服务器运行,所以Mysql不允许自定…...

华为USG6000E-S12防火墙Key exchange failed.无法SSH解决方案

由于目前防火墙算法太新,导致crt和xshell的版本无法登陆,按以下方法解决 一、下载华为本地加载除弱安全算法组件包之外的组件包 二、先改后缀名为.cfg,上传文件到防火墙 三、在用户视图下改后缀名为.mod 四、move 文件到$_install_mod文件夹 五、执行…...

matlab基础操作(五)

31.数组维数的减小 >> amagic(4),a(:,2)[] >> a(1,2)[] 带有下标的赋值维度不匹配。 >> a(2:4)[]%数组a将变为向量 32.元胞数组的创建 Cell indexing方式创建元胞数组 >> c(1,1){[1 4 3;0 5 8;7 2 9]} >> c(1,2){Anne Smith} >> c(2,1){…...

力扣 两数之和

致每一个初学算法的你。 题目 时间复杂度&#xff1a;O(N^2)&#xff0c; 空间复杂度&#xff1a;O(1) 。 class Solution {public int[] twoSum(int[] nums, int target) {int n nums.length;for (int i 0; i < n; i) {for (int j i 1; j < n; j) {if (nums[i] …...

Django 实现连续请求

创作灵感&#xff1a;工作中&#xff0c;前端因为某些原因&#xff08;极其特殊&#xff09;无法发送两个请求&#xff0c;需要后端实现 言归正传&#xff1a; 背景&#xff1a;使用djangoapscheduler实现定时任务&#xff0c;现在创建任务以及启动任务为两个接口&#xff0c…...

前端(react)框架nextjs

文章目录 一、什么是next.js1. 路由2. 打包 next build3. 部署 二、 next.js 和react区别三、webstorm使用nextjs四、开发常用总结如何修nextjs 启动监听的端口号&#xff1f;NGINX 反向代理 Next.js 项目配置 参考 一、什么是next.js 官网&#xff1a; https://www.nextjs.cn…...

深耕编程语言18年,对话 Rust、TypeScript、Nushell 核心贡献者 Sophia Turner | Open AGI Forum

作者 | Annie Xu 采访 | 卢威 责编 | Echo Tang 出品丨GOSIM 开源创新汇 编程语言的种类令人眼花缭乱&#xff0c;但成功的、常用的编程语言却是凤毛麟角。在深耕编程语言研发 18 年的 Sophia June Turner 看来&#xff0c;编程语言成功的关键在于其研发团队的透明度和机制建…...

深度学习--图像分割UNet介绍及代码分析

UNet介绍 参考UNet网络介绍整体架构UNet过程输入编码器&#xff08;下采样&#xff09;中间特征表示解码器&#xff08;上采样&#xff09;输出 代码详解unetUP和Unet关系上采样模块——unetUp用于图像分割的卷积神经网络&#xff08;CNN&#xff09;架构模块——Unet类的定义初…...

接了一个2000块的小活,大家进来看看值不值,附源码

如题&#xff0c;上周的一天&#xff0c;朋友圈的一个旧友找到了我&#xff0c;说让我帮他开发一个小工具&#xff0c;虽然活不大&#xff0c;但没个几年的全栈经验还不一定能接下来&#xff0c;因为麻雀虽小&#xff0c;涉及的内容可不少&#xff1a; 需求分析 原型设计 详细…...

基于MindFormers实现GPT2模型的推理

前言 针对MindFormers的安装&#xff0c;可参考本专栏里的另一篇博客 安装MindFormers&#xff08;昇腾910&#xff09;-CSDN博客 pipeline方式 from mindformers import pipeline from mindformers import GPT2LMHeadModel, GPT2Config, GPT2Tokenizer tok GPT2Tokenizer…...

探索腾讯云AI代码助手:智能编程的新时代

智能编程的新时代 前言开发环境介绍腾讯云 AI 代码助手使用实例生成文档解释代码生成测试修复代码人工智能技术对话 智能编程获得的帮助与提升对腾讯云AI代码助手的建议结语 前言 hello&#xff0c;大家好我是恒川&#xff0c;今天我来给大家安利一款非常好用的AI 代码助手&…...

MySQL 之 MHA 高可用架构详解

这个是在内部分享做的一个 Keynote 动画&#xff0c;用来演示 MHA 高可用架构及发生故障时的 Failover。动画如下&#xff1a; 数据库相关分享之 MySQL 的 MHA 架构详解 引言 MySQL 数据库在企业和应用中扮演着举足轻重的角色&#xff0c;其稳定性和可靠性对于业务的连续运行至…...

WangEditor自定义新元素,并解决自定义元素中换行无法消除样式的问题

一、背景概述 项目有自定义样式模板的需求&#xff0c;WangEditor没有。若直接把样式的html插入WangEditor中&#xff0c;无法解析&#xff0c;且会被自动过滤。因此&#xff0c;需要基于WangEditor提供的API进行二次开发。 例如&#xff0c;需要新增以下样式&#xff1a; 该…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

springboot 百货中心供应链管理系统小程序

一、前言 随着我国经济迅速发展&#xff0c;人们对手机的需求越来越大&#xff0c;各种手机软件也都在被广泛应用&#xff0c;但是对于手机进行数据信息管理&#xff0c;对于手机的各种软件也是备受用户的喜爱&#xff0c;百货中心供应链管理系统被用户普遍使用&#xff0c;为方…...

CMake基础:构建流程详解

目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)

本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...

给网站添加live2d看板娘

给网站添加live2d看板娘 参考文献&#xff1a; stevenjoezhang/live2d-widget: 把萌萌哒的看板娘抱回家 (ノ≧∇≦)ノ | Live2D widget for web platformEikanya/Live2d-model: Live2d model collectionzenghongtu/live2d-model-assets 前言 网站环境如下&#xff0c;文章也主…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合

作者&#xff1a;来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布&#xff0c;Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明&#xff0c;Elastic 作为 …...

面试高频问题

文章目录 &#x1f680; 消息队列核心技术揭秘&#xff1a;从入门到秒杀面试官1️⃣ Kafka为何能"吞云吐雾"&#xff1f;性能背后的秘密1.1 顺序写入与零拷贝&#xff1a;性能的双引擎1.2 分区并行&#xff1a;数据的"八车道高速公路"1.3 页缓存与批量处理…...

用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章

用 Rust 重写 Linux 内核模块实战&#xff1a;迈向安全内核的新篇章 ​​摘要&#xff1a;​​ 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言&#xff0c;受限于 C 语言本身的内存安全和并发安全问题&#xff0c;开发复杂模块极易引入难以…...