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进行二次开发。 例如,需要新增以下样式: 该…...
渗透实战PortSwigger靶场-XSS Lab 14:大多数标签和属性被阻止
<script>标签被拦截 我们需要把全部可用的 tag 和 event 进行暴力破解 XSS cheat sheet: https://portswigger.net/web-security/cross-site-scripting/cheat-sheet 通过爆破发现body可以用 再把全部 events 放进去爆破 这些 event 全部可用 <body onres…...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...
Linux 内存管理实战精讲:核心原理与面试常考点全解析
Linux 内存管理实战精讲:核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用,还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
加密通信 + 行为分析:运营商行业安全防御体系重构
在数字经济蓬勃发展的时代,运营商作为信息通信网络的核心枢纽,承载着海量用户数据与关键业务传输,其安全防御体系的可靠性直接关乎国家安全、社会稳定与企业发展。随着网络攻击手段的不断升级,传统安全防护体系逐渐暴露出局限性&a…...
GeoServer发布PostgreSQL图层后WFS查询无主键字段
在使用 GeoServer(版本 2.22.2) 发布 PostgreSQL(PostGIS)中的表为地图服务时,常常会遇到一个小问题: WFS 查询中,主键字段(如 id)莫名其妙地消失了! 即使你在…...
在Spring Boot中集成RabbitMQ的完整指南
前言 在现代微服务架构中,消息队列(Message Queue)是实现异步通信、解耦系统组件的重要工具。RabbitMQ 是一个流行的消息中间件,支持多种消息协议,具有高可靠性和可扩展性。 本博客将详细介绍如何在 Spring Boot 项目…...
break 语句和 continue 语句
break语句和continue语句都具有跳转作用,可以让代码不按既有的顺序执行 break break语句用于跳出代码块或循环 1 2 3 4 5 6 for (var i 0; i < 5; i) { if (i 3){ break; } console.log(i); } continue continue语句用于立即终…...
Python爬虫(四):PyQuery 框架
PyQuery 框架详解与对比 BeautifulSoup 第一部分:PyQuery 框架介绍 1. PyQuery 是什么? PyQuery 是一个 Python 的 HTML/XML 解析库,它采用了 jQuery 的语法风格,让开发者能够用类似前端 jQuery 的方式处理文档解析。它的核心特…...
