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

力扣 两数之和
致每一个初学算法的你。 题目 时间复杂度:O(N^2), 空间复杂度: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 实现连续请求
创作灵感:工作中,前端因为某些原因(极其特殊)无法发送两个请求,需要后端实现 言归正传: 背景:使用djangoapscheduler实现定时任务,现在创建任务以及启动任务为两个接口,…...

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

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

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

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

基于MindFormers实现GPT2模型的推理
前言 针对MindFormers的安装,可参考本专栏里的另一篇博客 安装MindFormers(昇腾910)-CSDN博客 pipeline方式 from mindformers import pipeline from mindformers import GPT2LMHeadModel, GPT2Config, GPT2Tokenizer tok GPT2Tokenizer…...

探索腾讯云AI代码助手:智能编程的新时代
智能编程的新时代 前言开发环境介绍腾讯云 AI 代码助手使用实例生成文档解释代码生成测试修复代码人工智能技术对话 智能编程获得的帮助与提升对腾讯云AI代码助手的建议结语 前言 hello,大家好我是恒川,今天我来给大家安利一款非常好用的AI 代码助手&…...
MySQL 之 MHA 高可用架构详解
这个是在内部分享做的一个 Keynote 动画,用来演示 MHA 高可用架构及发生故障时的 Failover。动画如下: 数据库相关分享之 MySQL 的 MHA 架构详解 引言 MySQL 数据库在企业和应用中扮演着举足轻重的角色,其稳定性和可靠性对于业务的连续运行至…...

WangEditor自定义新元素,并解决自定义元素中换行无法消除样式的问题
一、背景概述 项目有自定义样式模板的需求,WangEditor没有。若直接把样式的html插入WangEditor中,无法解析,且会被自动过滤。因此,需要基于WangEditor提供的API进行二次开发。 例如,需要新增以下样式: 该…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...

Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Nginx server_name 配置说明
Nginx 是一个高性能的反向代理和负载均衡服务器,其核心配置之一是 server 块中的 server_name 指令。server_name 决定了 Nginx 如何根据客户端请求的 Host 头匹配对应的虚拟主机(Virtual Host)。 1. 简介 Nginx 使用 server_name 指令来确定…...
Axios请求超时重发机制
Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式: 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...