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

东营 网站建设公司搜索引擎排名google

东营 网站建设公司,搜索引擎排名google,北京海淀区,西安网站建设的费用文章目录 一、环境二、没有泛型的Go三、泛型的优点四、理解泛型(一)定义(二)调用(三)类型约束(Type Constraint)1)接口与约束2)结构体类型约束3)类…

文章目录

  • 一、环境
  • 二、没有泛型的Go
  • 三、泛型的优点
  • 四、理解泛型
    • (一)定义
    • (二)调用
    • (三)类型约束(Type Constraint)
      • 1)接口与约束
      • 2)结构体类型约束
      • 3)类型近似(Type Approximations)
      • 4)泛型与结构体
    • (四)一些错误示例
      • 1)联合约束中的类型元素限制
      • 2)不含方法的接口只能用于类型参数
  • 五、参阅

一、环境

Go 1.20.2

二、没有泛型的Go

假设现在我们需要写一个函数,实现:
1)输入一个切片参数,切片类型可以是[]int[]float64,然后将所有元素相加的“和”返回
2)如果是int切片,返回int类型;如果是float64切片,返回float64类型

当然,最简单的方法是写两个函数SumSliceInt(s []int)SumSliceFloat64(s []float64)来分别支持不同类型的切片,但是这样会导致大部分代码重复冗余,不是很优雅。那么有没有办法只写一个函数呢?

我们知道,在Go中所有的类型都实现了interface{}接口,所以如果想让一个变量支持多种数据类型,我们可以将这个变量声明为interface{}类型,例如var slice interface{},然后使用类型断言(.(type))来判断这个变量的类型。

interface{} + 类型断言:

// any是inerface{}的别名,两者是完全相同的:type any = interface{}
func SumSlice(slice any) (any, error) {switch s := slice.(type) {case []int:sum := 0for _, v := range s {sum += v}return sum, nilcase []float64:sum := float64(0)for _, v := range s {sum += v}return sum, nildefault:return nil, fmt.Errorf("unsupported slice type: %T", slice)}
}

从上述代码可见,虽然使用interface{}类型可以实现在同一个函数内支持两种不同切片类型,但是每个case块内的代码仍然是高度相似和重复的,代码冗余的问题没有得到根本的解决。

三、泛型的优点

幸运的是,在Go 1.18之后开始支持了泛型(Generics),我们可以使用泛型来解决这个问题:

func SumSlice[T interface{ int | float64 }](slice []T) T {var sum T = 0for _, v := range slice {sum += v}return sum
}

是不是简洁了很多?而且,泛型相比interface{}还有以下优势:

  • 可复用性:提高了代码的可复用性,减少代码冗余。
  • 类型安全性:泛型在编译时就会进行类型安全检查,可以确保编译出来的代码就是类型安全的;而interface{}是在运行时才进行类型判断,如果编写的代码在类型判断上有bug或缺漏,就会导致Go在运行过程中报错。
  • 性能:不同类型的数据在赋值给interface{}变量时,会有一个隐式的装箱操作,从interface{}取数据时也会有一个隐式的拆箱操作,而泛型就不存在装箱拆箱过程,没有额外的性能开销。

四、理解泛型

(一)定义

编写一个函数,输入ab两个泛型参数,返回它们的和:

// T的名字可以更改,改成K、V、MM之类的都可以,只是一般比较常用的是T
// 这是一个不完整的错误例子
func Sum(a, b T) T {return a + b
}

大写字母T的名字叫类型参数(Type parameter),代表ab参数是泛型,可以接受多种类型,但具体可以接受哪些类型呢?在上面的定义中并没有给出这部分信息,要知道,并不是所有的类型都可以相加的,因此这里就引出了约束的概念,我们需要对T可以接受的类型范围作出约束:

// 正确例子
func Sum[T interface{ int | float64 }](a, b T) T {return a + b
}

中括号[]之间的空间用于定义类型参数,支持定义一个或多个

  • T:类型参数的名字
  • interface{ int | float64 }:对T的类型约束(Type Constraint),必须是一个接口,约束T只可以是intfloat64

为了简化写法,类型约束中的interface{}某些情况下是可以省略的,所以可以简写成:

func Sum[T int | float64](a, b T) T {return a + b
}

interface{}不能省略的一些情况:

// 当接口中包含方法时,不能省略
func Contains[T interface{ Equal() bool }](num T) {
}

可以定义多个类型参数:

func Add[T int, E float64](a T, b E) E {return E(a) + b
}

(二)调用

以上面的Sum泛型函数为例,完整的调用写法为:

Sum[int](1, 2)
Sum[float64](1.1, 2.2)

[]之间的内容称为类型实参(Type argument),是告诉编译器传过去的函数实参具体是什么类型。但大多数时候,编译器都可以自动推导出该类型,无需我们主动告知,这个功能叫函数实参类型推导(Function argument type inference)。所以可以简写成:

// 简写,跟调用普通函数一样的写法
Sum(1, 2)
Sum(1.1, 2.2)

需要注意的是,在调用这个函数时,ab两个参数的类型必须一致,要么两个都是int,要么都是float64,不能一个是int一个是float64

Sum(1, 2.3) // 编译会报错

什么时候不能简写?

// 当类型参数T仅用在返回值,没有用在函数参数列表时
func Foo[T int | float64]() T {return 1
}
Foo() // 报错:cannot infer T
Foo[int]() // OK
Foo[float64]() // OK

(三)类型约束(Type Constraint)

1)接口与约束

Go 使用interface定义类型约束。我们知道,在引入泛型之前,interface中只可以声明一组未实现的方法,或者内嵌其它interface,例如:

// 普通接口
type Driver interface {SetName(name string) (int, error)GetName() string
}// 内嵌接口
type ReaderStringer interface {io.Readerfmt.Stringer
}

接口里的所有方法称之为方法集(Method set)

引入泛型之后,interface里面可以声明的元素丰富了很多,可以是任何 Go 类型,包括基本类型、接口、方法等等,甚至struct结构体都可以,接口里的这些元素称为类型集(Type set)

// 基本类型约束
type MyInt interface {int
}// 结构体类型约束
type Point interface {struct{ X, Y int }
}// 内嵌其它约束
type MyNumber interface {MyInt
}// 联合(Unions)类型约束,不同类型元素之间是“或”的关系
// 如果元素是一个接口,这个接口不能包含任何方法!
type MyFloat interface {float32 | float64
}

有了丰富的类型集支持,我们就可以更加方便的使用接口对类型参数T的类型作出约束,既可以约束为基本类型(intfloat32string…),也可以约束它必须实现一组方法,灵活性大大增加。

因此前面的Sum函数还可以改写成:

// 原始例子:
// func Sum[T int | float64](a, b T) T {
//	 return a + b
// }type MyNumber interface {int | float64
}func Sum[T MyNumber](a, b T) T {return a + b
}

2)结构体类型约束

Go 还允许我们使用复合类型字面量来定义约束。例如,我们可以定义一个约束,类型元素是一个具有特定结构的struct

type Point interface {struct{ X, Y int }
}

然而,需要注意的是,虽然我们可以编写受此类结构体类型约束的泛型函数,但在当前版本的 Go 中,函数无法访问结构体的字段,例如:

func GetX[T Point](p T) int {return p.X  // p.X undefined (type T has no field or method X)
}

3)类型近似(Type Approximations)

我们知道,在Go中可以创建新的类型,例如:

type MyString string

MyString是一个新的类型,底层类型是string

在类型约束中,有时候我们可能并不关心上层类型,只要底层类型符合要求就可以,这时候就可以使用类型近似符号:~

// 创建新类型
type MyString string// 定义类型约束
type AnyStr interface {~string
}// 定义泛型函数
func Foo[T AnyStr](param T) T {return param
}func main() {var p1 string = "aaa"var p2 MyString = "bbb"Foo(p1)Foo(p2) // 虽然p2是MyString类型,但也可以通过泛型函数的类型约束检查
}

需要注意的是,类型近似中的类型,必须是底层类型,而且不能是接口类型:

type MyInt inttype I0 interface {~MyInt // 错误! MyInt不是底层类型, int才是~error // 错误! error是接口
}

4)泛型与结构体

前面都是以泛型函数为讲述例子,但其实泛型还可以用在struct结构体上。

假设我们现在要创建一个struct结构体,里面含有一个data泛型属性,类型是一个intfloat64的切片:

type List[T int | float64] struct {data []T
}

给这个结构体增加一个Sum方法,用于对切片求和:

func (l *List[T]) Sum() T {var sum Tfor _, v := range l.data {sum += v}return sum
}

实例化结构体,并调用Sum方法:

list := &List[int]{data: []int{1, 2, 3}}
sum := list.Sum()
fmt.Println(sum) // 输出:6

(四)一些错误示例

下面列出一些错误使用泛型的例子。

1)联合约束中的类型元素限制

联合约束中的类型元素不能是包含方法的接口:

// 错误
type ReaderStringer interface {io.Reader | fmt.Stringer // 错误,io.Reader和fmt.Stringer是包含方法的接口
}// 正确
type MyInt interface {int
}
type MyFloat interface {float32
}
type MyNumber interface {MyInt | MyFloat // 正确,MyInt和MyFloat接口里面没有包含方法
}

联合约束中的类型元素不能含有comparable接口:

type Number interface {comparable | int // 含有comparable,报错
}

2)不含方法的接口只能用于类型参数

不含方法的接口只能用于类型参数,不能用于变量、函数参数、返回值的类型声明:

type NoMethods interface {int
}// 错误
func Foo(param NoMethods) NoMethods {return param
}// 错误
var param NoMethods// 正确
func Foo[T NoMethods](param T) T {return param
}

五、参阅

  • Golang泛型
  • An Introduction To Generics
http://www.dtcms.com/wzjs/263021.html

相关文章:

  • 设计素材图片大全seo网站关键词优化
  • 称心的赣州网站建设青岛关键词排名系统
  • 做网站广告送报纸广告西安seo工作室
  • ECMS做的网站大数据分析营销平台
  • 政务信息公开和网站建设自评餐饮管理培训课程
  • 做图片素材的网站如何免费推广网站
  • 网站影响seo的标签百度电脑版网页版
  • 湘潭做网站找磐石网络一流seo是什么姓氏
  • 在市场部做网站多少工资南昌seo优化公司
  • notepad做网站技巧怎样打百度人工客服热线
  • 网站转应用互联网营销师有什么用
  • 网站安全维护公司seo积分优化
  • 深圳网站设计|优选灵点网络怎么注册自己公司的网址
  • 域名注册解析管理网站seo站长工具推广平台
  • 网站开发filter佛山网站建设维护
  • 成都建设网站报价公司建立网站的步骤
  • 网站移动端是什么情况看b站二十四小时直播间
  • 创新的菏泽网站建设优化的意思
  • 宝安住房和建设局网站推广营销是什么
  • 网站上传后徐州自动seo
  • 打码网站做的比较好的是哪些营销比较成功的品牌
  • 简要叙述如何规划建设一个企业网站营销推广活动策划方案
  • 大气装饰装修企业网站模版源码保定seo建站
  • 海口市建设工程质量安全监督站网站海口网站排名提升
  • 企业网站的建设企业百度竞价托管费用
  • 天津网站制作的公司外贸推广平台有哪几个
  • 渝北集团网站建设网络营销公司怎么注册
  • 贵阳做网站好的公司seo网络推广公司
  • 网站正在建设代码网站的优化从哪里进行
  • wordpress有多个页脚湖北seo诊断