美文网首页
go1.18探索 -- 泛型

go1.18探索 -- 泛型

作者: 米兰的小铁匠xxm | 来源:发表于2022-04-09 23:41 被阅读0次

go1.18终于发布了,据说支持了泛型,今天让我来一探究竟。

安装

执行如下命令

brew install go

确认安装完成

192:bin mason$ go version
go version go1.18 darwin/amd64

泛型讲解

先看个问题

在日常开发中我们经常会遇到判断数组是否包含某一元素的场景,举个例子:
1.判断int64数组中是否包含指定值
2.判断int32数组中是否包含指定值
3.判断string数组中是否包含指定值
4....
针对这种场景,通常我们会封装一些通用的方法,但由于go是强类型语言,我们只能针对每种类型单独封装一个方法,如下:

func ContainInt64(target int64, arr []int64) bool {
    for _,v := range arr {
        if v == target {
            return true
        }
    }
    return false
}

func ContainInt32(target int32, arr []int32) bool {
    for _,v := range arr {
        if v == target {
            return true
        }
    }
    return false
}

func ContainString(target string, arr []string) bool {
    for _,v := range arr {
        if v == target {
            return true
        }
    }
    return false
}

上述方法除类型外,实现逻辑是一样的,会导致存在大量重复代码。那有什么方法能避免这个问题呢?你可能会想到反射,判断输入值的类型然后做相应的判断,这样其实把类型判断放到了函数内部,可维护性和可读性依然会比较差。我们需要的其实是一个function能支持多种不同类型,而泛型的出现正好解决了这一问题。

什么是泛型

泛型允许程序员在强类型程序设计语言中编写代码时使用一些以后才指定的类型,在实例化时作为参数指明这些类型,如C++中的模板。

go的泛型

go的泛型包括了泛型函数和泛型类型两部分。借助一个示例来说下什么是泛型函数,我们回到开头说的判断数组是否包含某元素的例子,使用泛型该如何处理呢?示例如下:

func main() {
    fmt.Println(ContainElement(1, []int32{1,2,3}))
    fmt.Println(ContainElement("1", []string{"a","1","b"}))
    fmt.Println(ContainElement("1", []string{"a","c","b"}))
}

func ContainElement[T int64 | int32 | string](target T, arr []T) bool {
    for _,v := range arr {
        if v == target {
            return true
        }
    }
    return false
}
//输出
true
true
false

可以看到相较于之前的函数写法,多了参数列表[T int64 | int32 | string],参数列表包括参数名(T)和约束(int64 | int32 | string)两部分,其中|表示取并集,即T可为int64、int32和string三种类型中的任意一种。
当类型较多时,约束会比较长,且多个泛型函数之间可能会使用相同的约束,此时我们可以对约束类型进行简化,如下:

func main() {
    fmt.Println(ContainElement(1, []int32{1,2,3}))
    fmt.Println(ContainElement("1", []string{"a","1","b"}))
    fmt.Println(ContainElement("1", []string{"a","c","b"}))
    fmt.Println(Sum(1,2))
    fmt.Println(Sum("hello ","world"))
}

type commonType interface {
  int | int64 | int32 | string
}

func ContainElement[T commonType](target T, arr []T) bool {
    for _,v := range arr {
        if v == target {
            return true
        }
    }
    return false
}

func Sum[T commonType](a T, b T) T {
    return a + b
}
//输出
true
true
false
3
hello world

写到这儿泛型函数的使用方法大家基本都清楚了吧,golang还有一种泛型类型,大概意思就是对类型进行泛型并支持定义相关的类型函数,举个简单例子吧

type Vector[T int|string] []T

func (v *Vector[T])push (x T)  {
    *v = append(*v,x)
}

func (v *Vector[T]) Add () T {
    var res T
    for _,v1 := range *v {
        res += v1
    }
    return res
}

func main()  {
    var strs Vector[string]
    strs.push("aaa,")
    strs.push("bbb,")
    strs.push("ccc")
    fmt.Println(strs.Add())

    var ints Vector[int]
    ints.push(1)
    ints.push(2)
    ints.push(3)
    fmt.Println(ints.Add())
}
//输出
aaa,bbb,ccc
6

性能

  1. 由于支持泛型,go1.18预计比go.1.17编译速度慢15%,运行时间不受影响,目前计划在 Go1.19中提高编译器的速度。
  2. 20% 性能提升:对于使用Apple M1、ARM64 和 PowerPC64 用户,由于 Go 1.17 的寄存器 ABI 调用约定扩展到这些架构,Go 1.18 包括高达 20% 的 CPU 性能改进。

最后

时间有限,先写到这儿吧。最后总结一下,什么情况下用泛型呢?我认为只要是参数类型不同而操作行为相同的场景都可以使用泛型进行重构。

相关文章

  • go1.18探索 -- 泛型

    go1.18终于发布了,据说支持了泛型,今天让我来一探究竟。 安装 执行如下命令 确认安装完成 泛型讲解 先看个问...

  • Swift探索( 九): 泛型

    一: 泛型 1.1 什么是泛型 泛型可以将类型参数化,提高代码复用效率,减少代码量。 1.2 泛型解决的问题 下面...

  • 教你如何完全解析Kotlin中的注解

    简述: 从这篇文章将继续开始探索Kotlin中的一些高级的内容,之前有着重探讨了Kotlin的泛型以及泛型型变等内...

  • 泛型 & 注解 & Log4J日志组件

    掌握的知识 : 基本用法、泛型擦除、泛型类/泛型方法/泛型接口、泛型关键字、反射泛型(案例) 泛型 概述 : 泛型...

  • 【泛型】通配符与嵌套

    上一篇 【泛型】泛型的作用与定义 1 泛型分类 泛型可以分成泛型类、泛型方法和泛型接口 1.1 泛型类 一个泛型类...

  • 泛型的使用

    泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法 泛型类 泛型接口 泛型通配符 泛型方法 静态方法与...

  • Java 泛型

    泛型类 例如 泛型接口 例如 泛型通配符 泛型方法 类中的泛型方法 泛型方法与可变参数 静态方法与泛型 泛型上下边...

  • 探秘 Java 中的泛型(Generic)

    本文包括:JDK5之前集合对象使用问题泛型的出现泛型应用泛型典型应用自定义泛型——泛型方法自定义泛型——泛型类泛型...

  • Web笔记-基础加强

    泛型高级应用 自定义泛型方法 自定义泛型类 泛型通配符? 泛型的上下限 泛型的定义者和泛型的使用者 泛型的定义者:...

  • 重走安卓进阶路——泛型

    ps.原来的标题 为什么我们需要泛型? 泛型类、泛型接口和泛型方法(泛型类和泛型接口的定义与泛型方法辨析); 如何...

网友评论

      本文标题:go1.18探索 -- 泛型

      本文链接:https://www.haomeiwen.com/subject/wusmsrtx.html