• Go语言学习笔记——Golang 1.18新特性泛型



    Golang 1.18新特性泛型

    一 什么是泛型

    泛型的英文是Generics,就是函数的参数,或者容器元素的类型,支持更广泛的类型,不再是特定的类型。

    在Golang、Java、C++等这类静态语言中,是需要严格定义传入变量的类型的,斌不是随心所欲,例如在golang中:

    func Sum(a, b int) int {
       
      return a + b
    }
    
    • 1
    • 2
    • 3
    • 4

    在函数Sum中,不仅要严格定义传入参数a和b的变量类型,而且返回值的类型也需要严格定义,所有你只能传入int类型进行调用:

    Sum(1, 2) // 3
    
    • 1

    如果传入其它类型的变量就会报错:

    fmt.Println(Sum(1.23, 2.54)); 
     
    ./main.go:33:18: cannot use 1.23 (untyped float constant) as int value in argument to Sum (truncated)
    ./main.go:33:24: cannot use 2.54 (untyped float constant) as int value in argument to Sum (truncated)
    
    • 1
    • 2
    • 3
    • 4

    因此,如果当golang开发者想开发类似实现两个float类型变量相加的功能,只能另写一个函数:

    func SumFloat(a, b float) float {
       
      return a + b
    }
    
    • 1
    • 2
    • 3
    • 4

    或者写一个通用的Sum函数使用interface反射来判断:

    func Sum(a, b interface{
       }) interface{
       } {
       
      switch a.(type) {
       
      case int:
        a1 := a.(int)
        b1 := b.(int)
        return a1 + b1
      case float64:
        a1 := a.(float64)
        b1 := b.(float64)
        return a1 + b1
      default:
        return nil
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    这样的话,不仅重复很多代码,而且类型频繁转换导致不仅性能低效,安全性上也不高。

    所以泛型诞生了。

    然而泛型是一把双刃剑,在给开发者带来便利的同时,同样会带来编译和效率的问题,因为泛型需要系统去推倒和计算变量的类型的,这在无形中会增加编译的时间和降低运行效率

    二 Golang中的泛型

    首先来看一下,在Golang 1.18版本中是如何利用泛型来实现Sum函数的

    func Sum[T int|float64](a,b T) T {
       
      return a + b
    }
    
    • 1
    • 2
    • 3
    • 4

    然后再调用一下:

    fmt.Println(Sum[int](1, 2))  //3
    fmt.Println(Sum[float64](1.23, 2.54))  //3.77
    
    • 1
    • 2

    先不去理解函数中各组件的含义,仅仅看代码就简洁了不少,乙肝函数就实现了多个类型的功能。

    因为泛型针对的是类型变量,在golang中,类型是贯穿整个语法生态的,比如:变量、函数、接口、通道等。

    三 泛型语法详解

    3.1 泛型的语法

    MyType[T1 constraint1 | constraint2, T2 constraint3...] ... 
    
    • 1

    泛型的语法非常简单, 就类似于上面这样, 其中:

    • MyType可以是函数名, 结构体名, 类型名…
    • T1, T2…是泛型名, 可以随便取
    • constraint的意思是约束, 也是泛型中最重要的概念, 接下来会详解constraint
    • 使用 | 可以分隔多个constraint, T满足其中之一即可(如T1可以是constraint1constraint2中的任何一个)

    3.2 Constraint(约束)是什么

    约束的意思是限定范围, constraint的作用就是限定范围, 将T限定在某种范围内

    而常用的范围, 我们自然会想到的有:

    • any(interface{}, 任何类型都能接收, 多方便啊!)
    • Interger(所有int, 多方便啊, int64 int32…一网打尽)
    • Float(同上)
    • comparable(所有可以比较的类型, 我们可以给所有可以比较的类型定制一些方法)

    这些约束, 不是被官方定义为内置类型, 就是被涵盖在了constraints包内!!!

    下面是builtin.go的部分官方源码:

    // any is an alias for interface{} and is equivalent to interface{} in all ways.
    type any = interface{
       }
    
    // comparable is an interface that is implemented by all comparable types
    // (booleans, numbers, strings, pointers, channels, interfaces,
    // arrays of comparable types, structs whose fields are all comparable types).
    // The comparable interface may only be used as a type parameter constraint,
    // not as the type of a variable.
    type comparable comparable
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    下面是constraints.go的部分官方源码:

    // Integer is a constraint that permits any integer type.
    // If future releases of Go add new predeclared integer types,
    // this constraint will be modified to include them.
    type Integer interface {
       
    	Signed | Unsigned
    }
    
    // Float is a constraint that permits any floating-point type.
    // If future releases of Go add new predeclared floating-point types,
    // this constraint will be modified to include them.
    type Float interface {
       
    	~float32 | ~float64
    }
    //......
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    3.3 自定义constraint(约束)

    下面是constraints包中的官方源码:

    type Signed interface {
       
    	~int | ~int8 | ~int16 |
    • 1
    • 2
  • 相关阅读:
    【java吐血整理】
    双十一蓝牙耳机推荐哪款?发烧友推荐目前最值得入手的蓝牙耳机
    有一个不错的解决module xxx has no attribute的思路
    Linux中通配符的使用
    SpringBoot3 配置Logback日志滚动文件
    音视频开发进阶——YUV与RGB的采样与存储格式
    Google vs IBM vs Microsoft: 哪个在线数据分析师证书最好
    pycharm2023.3专业版安装后打开无反应
    linux-任务计划和日志管理
    【Java八股文之进阶篇(五)】多线程编程核心之并发容器
  • 原文地址:https://blog.csdn.net/qq_39280718/article/details/126786517