东莞网站推广哪里好/山东工艺美术学院网站建设公司

东莞网站推广哪里好,山东工艺美术学院网站建设公司,太原代理记账,永州公司做网站泛型从 go 的 1.18 开始支持 什么是泛型编程 在泛型出现之前,如果需要计算两数之和,可能会这样写: func Add(a, b int) int {returb a b } 这个很简单,但是只能两个参数都是 int 类型的时候才能调用 如果想要计算两个浮点数…

泛型从 go 的 1.18 开始支持

什么是泛型编程

在泛型出现之前,如果需要计算两数之和,可能会这样写:

func Add(a, b int) int {returb a + b
}

这个很简单,但是只能两个参数都是 int 类型的时候才能调用

如果想要计算两个浮点数的和,就需要再定义一个函数

func AddFloat32(a, b float32) float32 {return a + b
}

如果需要计算两个字符串的和,就需要再定义一个函数,这样太过麻烦

在一个函数中,行参只是类似占位符的东西,只有调用函数传入实参之后才有具体的值

如果把行参、实参的概念推广一下,给变量的类型也引入类似行参实参的概念,那就可以接收各种类型的值

函数就类似于:

func Add(a, b T) T {return a + b
}

在这段代码中,T 可以称为 类型行参(type parameter),它不是具体的类型,在定义函数时参数的类型不确定,在传入时才确定,传入参数的具体类型称为 类型实参(type argument)

这样通过 类型行参类型实参 进行编码的方式就称为 泛型编程

Go 的泛型

除了上面提到的类型行参和类型实参,Go 还引入了其他概念:

  • 类型形参 (Type parameter)

  • 类型实参(Type argument)

  • 类型形参列表( Type parameter list)

  • 类型约束(Type constraint)

  • 实例化(Instantiations)

  • 泛型类型(Generic type)

  • 泛型接收器(Generic receiver)

  • 泛型函数(Generic function)

一个一个说

类型行参、类型实参、类型约束和泛型类型

假如现在要定义一个切片,可以容纳 int、float32、string 等多种类型,不使用泛型常规做法是为每种类型各自定义一个切片

使用泛型,就可以这样定义:

type AllTypeSlice[T int | float32 | string] []T

在这行代码中:

  • T 就是上面介绍的 类型参数,在定义 slice 时 T 的类型不确定,类似于一个占位符

  • int|float|string 称为 类型约束,中间的 | 就是告诉编译器只能接收这几种类型中的一种

  • 中括号[] 中的 T int|float32|float64 这一整串定义了所有的类型实参(这里只有 T 这一个类型行参),称为 类型行参列表

泛型类型不能拿来使用,必须传入类型实参,能确定类型后才能使用,这个过程称为 实例化

func main() {type AllTypeSlice[T int | float32 | string] []T
​intSlice := AllTypeSlice[int]{}fmt.Printf("%T\n", intSlice) // main.AllTypeSlice[int]
​floatSlice := AllTypeSlice[float32]{}fmt.Printf("%T\n", floatSlice) // main.AllTypeSlice[float32]
}

类型行参的个数可以有多个,比如:

type AllTypeMap[KEY int | string, VALUE float32 | float64] map[KEY]VALUE

这样就定义了一个泛型 map,key 和 value 都可以是多种

func main() {type AllTypeMap[KEY int | string, VALUE float32 | float64] map[KEY]VALUE
​var a AllTypeMap[string, float64] = map[string]float64{"jack_score": 9.6,"bob_score":  8.4,}fmt.Printf("%T\n", a) // main.AllTypeMap[string,float64]
}
其他的泛型类型

所有类型定义都可以使用类型行参,包括结构体、接口、通道

// 泛型结构体
type AllTypeStruct[T int | string] struct {Name stringData T
}
​
// 泛型接口
type PrintData[T int | float32] interface {Print(data T)
}
​
// 泛型通道
type AllTypeChan[T int | string] chan T
类型行参的嵌套

类型行参是可以嵌套使用的,比如:

type AllTypeStruct[T int | float32, S []T] struct {Data     SMaxValue TMinValue T
}

使用:

s1 := AllTypeStruct[int, []int]{}
s2 := AllTypeStruct[int, []float32]{} // 报错 类型需要一致

即使 T 可以从 int 和 float32 中选,但是传入时类型已经确定了,所以 T 的类型和 []T 中 T 的类型要保持一致

泛型的使用

泛型一般用来实现一些不需要关注具体类型就可以使用的通用方法

给出一个比较常用的场景:Gorm 中使用泛型写一些基础方法,不同类型调用这些方法,会使用对应的 model,通过相同的逻辑查不同的表,而不需要再分别写各自的方法

常见的一些通用方法:

func IsErrRecordNotFound(err error) bool {return errors.Is(err, gorm.ErrRecordNotFound)
}
​
type baseRepo[T any] struct {db *gorm.DB
}
​
func NewBaseRepo[T any](db *gorm.DB) baseRepo[T] {return baseRepo[T]{db: db}
}
​
func (r *baseRepo[T]) GetDB() *gorm.DB {return r.db
}
​
// GetByID 通过 id 查单条记录
func (r *baseRepo[T]) GetByID(id int, preloads ...string) (*T, error) {var result Tdb := r.dbfor _, preload := range preloads {db = db.Preload(preload)}if err := db.First(&result, id).Error; err != nil {return nil, err}return &result, nil
}
​
// GetByIds 通过 ids 用 IN 查结果集
func (r *baseRepo[T]) GetByIds(ids []int, preloads ...string) (list []*T, err error) {db := r.dbfor _, preload := range preloads {db = db.Preload(preload)}err = db.Unscoped().Where("id IN ?", ids).Find(&list).Errorreturn
}
​
// GetFirst 根据条件查第一条记录 传入对应类型结构体
func (r *baseRepo[T]) GetFirst(cond T, preloads ...string) (*T, error) {var result Tdb := r.dbfor _, preload := range preloads {db = db.Preload(preload)}if err := db.First(&result, cond).Error; err != nil {if IsErrRecordNotFound(err) {return nil, nil}return nil, err}return &result, nil
}
​
// GetList 通过条件查所有记录
func (r *baseRepo[T]) GetList(cond T, preloads ...string) ([]*T, error) {var list []*Tdb := r.dbfor _, preload := range preloads {db = db.Preload(preload)}if err := db.Find(&list, cond).Error; err != nil {return nil, err}return list, nil
}
​
// GetListWithOrder 根据条件查询所有记录并排序
func (r *baseRepo[T]) GetListWithOrder(cond T, order string, preloads ...string) ([]*T, error) {var list []*Tdb := r.dbfor _, preload := range preloads {db = db.Preload(preload)}if err := db.Order(order).Find(&list, cond).Error; err != nil {return nil, err}return list, nil
}
​
// GetPage 分页查询记录
func (r *baseRepo[T]) GetPage(cond *T, order string, pageNo, pageSize int, preloads ...string) ([]*T, error) {db := r.dbfor _, preload := range preloads {db = db.Preload(preload)}
​offset := (pageNo - 1) * pageSizelimit := pageSizedb = db.Order(order).Offset(offset).Limit(limit)if cond != nil {db = db.Where(cond)}
​var list []*Tif err := db.Find(&list).Error; err != nil {return nil, err}return list, nil
}
​
// LikeWithOrder 模糊查询并排序
func (r *baseRepo[T]) LikeWithOrder(columns []string, keyword, order string, preloads ...string) ([]*T, error) {var list []*Tdb := r.dbfor _, preload := range preloads {db = db.Preload(preload)}like := "%" + keyword + "%"for _, column := range columns {query := fmt.Sprintf("%s like ?", column)db = db.Or(query, like)}if err := db.Order(order).Find(&list).Error; err != nil {return nil, err}return list, nil
}
​
// GetAll 查询所有记录
func (r *baseRepo[T]) GetAll(preloads ...string) ([]*T, error) {var list []*Tdb := r.dbfor _, preload := range preloads {db = db.Preload(preload)}if err := db.Find(&list).Error; err != nil {return nil, err}return list, nil
}
​
// GetIds 通过条件查 ids
func (r *baseRepo[T]) GetIds(cond T) ([]int, error) {var ids []intmodel := new(T)if err := r.db.Model(model).Where(cond).Pluck("id", &ids).Error; err != nil {return nil, err}return ids, nil
}
​
// UpdateById 更新单个属性
func (r *baseRepo[T]) UpdateById(id int, column string, value any) error {m := new(T)return r.db.Model(m).Where("id = ?", id).Update(column, value).Error
}
​
// UpdatesById 更新多个属性值,可以传 map 或者结构体
func (r *baseRepo[T]) UpdatesById(id int, updateInfo interface{}) error {m := new(T)return r.db.Model(m).Where("id = ?", id).Updates(updateInfo).Error
}
​
// DeleteByID 删除一条记录
func (r *baseRepo[T]) DeleteByID(id int, force ...bool) error {m := new(T)session := r.db.Model(m)if len(force) > 0 && force[0] == true {session = session.Unscoped()}return session.Delete(m, id).Error
}
​
// DeleteBatch 删除多条记录
func (r *baseRepo[T]) DeleteBatch(ids []int, force ...bool) error {m := new(T)session := r.db.Where("id IN ?", ids)if len(force) > 0 && force[0] == true {session = session.Unscoped()}return session.Delete(m).Error
}
​
// DeleteWith 通过条件删除记录
func (r *baseRepo[T]) DeleteWith(cond T, force ...bool) error {m := new(T)session := r.db.Where(cond)if len(force) > 0 && force[0] == true {session = session.Unscoped()}return session.Delete(m).Error
}
​
// Count 查询记录条目数
func (r *baseRepo[T]) Count(cond T) (int, error) {var num int64m := new(T)err := r.db.Model(m).Where(cond).Count(&num).Errorreturn int(num), err
}

这些方法都是一些逻辑比较简单的通用方法,在使用时,只需要通过结构体嵌套的方式注入 baseRepo ,在查询时就可以直接使用,很方便

结语

对于泛型,我认为只需要掌握基础的使用方法,一些细节和高级用法需要用到时再去查询比较合适,重点在于日常使用

参考(真的很详细,推荐阅读):后端 - Go 1.18 泛型全面讲解:一篇讲清泛型的全部 - 个人文章 - SegmentFault 思否

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

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

相关文章

IoTDB 与 HBase 对比详解:架构、功能与性能

五大方向,洞悉 IoTDB 与 HBase 的详尽对比! 在物联网(IoT)领域,数据的采集、存储和分析是确保系统高效运行和决策准确的重要环节。随着物联网设备数量的增加和数据量的爆炸式增长,开发者和决策者们需要选择…

单片机串口接收状态机STM32

单片机串口接收状态机stm32 前言 项目的芯片stm32转国产,国产芯片的串口DMA接收功能测试不通过,所以要由原本很容易配置的串口空闲中断触发DMA接收数据的方式转为串口逐字节接收的状态机接收数据 两种方式各有优劣,不过我的芯片已经主频跑…

词嵌入方法(Word Embedding)

词嵌入方法(Word Embedding) Word Embedding是NLP中的一种技术,通过将单词映射到一个空间向量来表示每个单词 ✨️常见的词嵌入方法: 🌟Word2Vec:由谷歌提出的方法,分为CBOW(conti…

【go从零单排】实现枚举类型(Enum)

🌈Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 📗概念 在Go语言中,并没有内置的枚举类型(Enum)&…

Python爬虫如何处理验证码与登录

Python爬虫如何处理验证码与登录 Python 爬虫在抓取需要登录的网站数据时,通常会遇到两个主要问题:登录验证和验证码处理。这些机制是网站用来防止自动化程序过度抓取数据的主要手段。本文将详细讲解如何使用 Python 处理登录与验证码,以便进…

MOS管损坏原因

MOS管是什么? MOS管,全程就是MOSFET(Metal-Oxide-Semiconductor Field-Effect Transistor),是一种场效应晶体管。‌ MOS管控制原理 MOS管的工作原理是通过栅极电压(G)来控制源极&#xff08…

「QT」QT5程序设计专栏目录

✨博客主页何曾参静谧的博客📌文章专栏「QT」QT5程序设计📚全部专栏「VS」Visual Studio「C/C」C/C程序设计「UG/NX」BlockUI集合「Win」Windows程序设计「DSA」数据结构与算法「UG/NX」NX二次开发「QT」QT5程序设计「File」数据文件格式「PK」Parasolid…

论文阅读《机器人状态估计中的李群》

目录 摘要1 介绍2 微李理论2.1 李群 摘要 李群是一个古老的数学抽象对象,可以追溯到19世纪,当时数学家 Sophus Lie奠定了连续变换群理论的基础。多年后,它的影响已经蔓延到科学和技术的各个领域。在机器人领域,我们最近正在经历一…

EHOME视频平台EasyCVR视频融合平台使用OBS进行RTMP推流,WebRTC播放出现抖动、卡顿如何解决?

在现代视频监控领域,跨区域的网络化视频监控管理平台成为了大中型项目的首选。EHOME视频平台EasyCVR以其强大的功能和兼容性,成为了众多项目的核心组件。它不仅能够管理视频资源、设备、用户、运维和安全,还支持多种行业标准协议,…

浮动路由:实现出口线路的负载均衡冗余备份。

浮动路由 Tip:浮动路由指在多条默认路由基础上加入优先级参数,实现出口线路冗余备份。 ip routing-table //查看路由表命令 路由优先级参数:越小越优 本次实验测试两条默认路由,其中一条默认路由添加优先级参数,设置…

Android CCodec Codec2 (十九)C2LinearBlock

在上一篇文章的结尾,我们看到fetchLinearBlock方法最终创建了一个C2LinearBlock对象。这一节,我们将深入了解C2LinearBlock是什么,它的作用是什么,以及它是如何被创建的。 1、_C2BlockFactory 先对上一篇文章的结尾内容做简单回顾…

Axure PR 9 多级下拉选择器 设计交互

​ 大家好,我是大明同学。 Axure选择器是一种在交互设计中常用的组件,这期内容,我们来探讨Axure中多级下拉选择器设计与交互技巧。 下拉列表选择输入框元件 创建选择输入框所需的元件 1.在元件库中拖出一个矩形元件。 2.选中矩形元件&…

SparkSql读取数据的方式

一、读取普通文件 方式一:给定读取数据源的类型和地址 spark.read.format("json").load(path) spark.read.format("csv").load(path) spark.read.format("parquet").load(path) 方式二:直接调用对应数据源类型的方法 …

使用Python实现图像的手绘风格效果

使用Python实现图像的手绘风格效果 一、引言二、代码详细解释与示例三、完整框架流程四、运行五、结论附:完整代码 一、引言 在数字图像处理领域,模拟手绘风格是一项有趣且具有挑战性的任务。手绘风格图像通常具有独特的纹理和深浅变化,给人…

Oracle Select语句

SELECT语句使用方法 在Oracle中,表是由列和行组成。 例如,示例数据库中的customers表具有以下列:customer_id,name,address,website和credit_limit。customers表中这些列中也有对应的数据。 要从表的一个或…

w~大模型~合集21

我自己的原文哦~ https://blog.51cto.com/whaosoft/12459590 #大模型~微调~用带反馈的自训练 面对当前微调大模型主要依赖人类生成数据的普遍做法,谷歌 DeepMind 探索出了一种减少这种依赖的更高效方法。大模型微调非得依赖人类数据吗?用带反馈的自训…

ctfshow(316,317,318)--XSS漏洞--反射性XSS

反射型XSS相关知识 Web316 进入界面: 审计 显示是关于反射性XSS的题目。 思路 首先想到利用XSS平台解题,看其他师傅的wp提示flag是在cookie中。 当前页面的cookie是flagyou%20are%20not%20admin%20no%20flag。 但是这里我使用XSS平台,…

【案例】Excel使用宏来批量插入图片

一、场景介绍 我有一个excel文件,需要通过一列的文件名称,按照规则给批量上传图片附件。 原始文件: 成功后文件: 二、实现方法 1. 使用【wps】工具打开Excel文件,将其保存为启用宏的文件。 2.找到编辑宏的【VB编辑器…

ENSP OSPF和BGP引入

路由协议分为:内部网关协议和外部网关协议。内部网关协议用于自治系统内部的路由,包括:RIP和OSPF。外部网关协议用于自治系统之间的路由,包括BGP。内部网关协议和外部网关协议配合来共同完成网络的路由。 BGP:边界网关路由协议(b…

Linux磁盘存储

磁盘存储 设备文件 设备文件是类Unix操作系统(包括Linux)中一种特殊的文件类型,它代表了设备接口,使得用户空间的程序可以通过标准的文件操作来访问和控制硬件设备。设备文件为周边设备提供了简单的接口,如打印机、硬…