Go 1.18新特性之泛型的全面讲解

yizhihongxing

Go 1.18新特性之泛型的全面讲解

背景介绍

在软件开发过程中,我们经常需要使用数据结构(如列表、树、哈希表等)和算法(如排序、查找、遍历等)。在现有的编程语言中,使用这些数据结构和算法都需要我们重复编写许多相似的代码,这不仅浪费时间,也容易引入bug。因此,一种可以重复使用的通用代码块,也就是“泛型”,成为了程序员们迫切需要的功能之一。

在Go语言的早期版本中,它并不支持泛型,在某种程度上约束了Go语言在编写通用代码块方面的能力。不过,Go 1.18版本带来了一种全新的泛型实现方式,这使得在Go语言中编写更高效、更简洁、更易维护的通用代码变得更加容易和自然。

泛型的基本概念

泛型是指一种通用的编程方式,它可以使不同的数据类型和算法共用相同的代码结构,从而达到重复使用、减少代码冗余、提高代码复用性等目标。一种常见的泛型编程方式是使用类型参数,以此来表示不确定的类型,比如:

func Swap[T any](a,b *T) {
    tmp := *a
    *a = *b
    *b = tmp
}

该函数使用了类型参数T,并且T继承了any类型,表示它可以是任意类型。在调用该函数时,编译器会根据实际的参数类型来推断T的具体类型。例如:

a := 1
b := 2
Swap(&a, &b) // a = 2, b = 1

c := "hello"
d := "world"
Swap(&c, &d) // c = "world", d = "hello"

从中可以看到,我们不用在编写不同类型的swap函数时重复编写相似的代码,只需在同一个函数中通过泛型实现即可,更加简洁易懂。

泛型的特性

Go 1.18版本中提供的泛型支持具有以下特性:

  1. 类型参数:可以在函数或结构体定义中定义类型参数,使用时根据实际情况传递具体类型。

  2. 接口约束:类型参数可以约束为只接受实现了特定接口的类型。

  3. 类型约束:类型参数可以约束为只接受特定类型,可以使用intstring和任意已知的类型、也可以使用其他泛型类型参数作为约束。

  4. 泛型函数:支持定义泛型函数,并使用类型参数来推断和调用该函数。

  5. 泛型结构体:支持定义泛型结构体,并使用类型参数来推断和初始化结构体。

示例说明

泛型函数

在下面的示例中,我们使用LinkNode泛型类型来实现一个通用的链表,其中使用NewList函数来创建链表,使用Append函数来添加元素。相比于在旧版本的Go语言中,需要分别编写intstring类型的链表,使用泛型实现可以显著提高代码复用性。

package main

import "fmt"

type LinkNode[T any] struct {
    Value T
    next *LinkNode[T]
}

func NewList[T any]() *LinkNode[T] {
    return nil
}

func Append[T any](node *LinkNode[T], value T) *LinkNode[T] {
    if node == nil {
        return &LinkNode[T]{Value: value, next: nil}
    }
    node.next = Append(node.next, value)
    return node
}

func main() {
    list := NewList[int]()
    for i := 0; i < 10; i++ {
        list = Append(list, i)
    }
    for node := list; node != nil; node = node.next {
        fmt.Println(node.Value)
    }
}

泛型结构体

在下面的示例中,我们使用Stack泛型结构体来实现一个通用的栈,Push用来添加元素,Pop用来弹出元素。其中T是泛型类型参数,表示栈中存储的元素类型。相比于在旧版本的Go语言中,需要分别编写intstring类型的栈,使用泛型实现可以显著提高代码复用性。

package main

import "fmt"

type Stack[T any] struct {
    top  int
    data []T
}

func NewStack[T any]() *Stack[T] {
    return &Stack[T]{0, make([]T, 10)}
}

func (s *Stack[T]) Push(value T) {
    if s.top >= len(s.data) {
        // 栈已满,扩容
        newdata := make([]T, s.top+10)
        for i, v := range s.data {
            newdata[i] = v
        }
        s.data = newdata
    }
    s.data[s.top] = value
    s.top++
}

func (s *Stack[T]) Pop() T {
    if s.top <= 0 {
        panic("stack is empty")
    }
    s.top--
    return s.data[s.top]
}

func main() {
    intstack := NewStack[int]()
    intstack.Push(10)
    intstack.Push(20)
    fmt.Printf("%d, %d\n", intstack.Pop(), intstack.Pop())

    stringstack := NewStack[string]()
    stringstack.Push("hello")
    stringstack.Push("world")
    fmt.Printf("%s, %s\n", stringstack.Pop(), stringstack.Pop())
}

结论

泛型作为一种通用的编程方式,在Go语言中得以完美落地,能够显著提高代码复用性,降低编程难度和维护成本。并且,由于Go语言泛型的实现方式与其它语言有所不同,因此也能够避免类型装箱、拆箱等转换过程,性能表现尤为卓越。在Go语言的未来开发中,泛型将成为Go语言编程的核心能力之一。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Go 1.18新特性之泛型的全面讲解 - Python技术站

(0)
上一篇 2023年6月27日
下一篇 2023年6月27日

相关文章

  • CMD里或登陆远程linux服务器时命令行下复制和粘贴实现方法

    要在CMD命令行或远程登录Linux服务器的命令行下实现复制和粘贴,可以通过以下几种方法: 1. 使用鼠标右键复制和粘贴 在Windows系统下,可以在CMD命令行窗口中,使用鼠标右键来复制和粘贴文本。具体操作如下: 复制:选中要复制的文本,然后右键单击选中的文本,选择“复制”命令,或者直接按下“Enter”键即可将文本复制到系统剪贴板中。 粘贴:右键单击C…

    other 2023年6月26日
    00
  • Git在项目协作开发中所解决问题

    Git在项目协作开发中所解决问题的完整攻略 Git是一个分布式版本控制系统,它在项目协作开发中解决了许多问题。下面是一个详细的攻略,介绍了Git在项目协作开发中的应用和解决问题的方法。 1. 版本控制 Git可以跟踪项目中的每个文件的修改历史,包括添加、删除和修改操作。这使得团队成员可以随时查看和恢复之前的版本,避免了意外修改或删除文件的风险。 示例说明: …

    other 2023年7月27日
    00
  • latticeplanner规划详解

    以下是详细讲解“latticeplanner规划详解”的标准Markdown格式文本,包含两个示例说明: latticeplanner规划详解 latticeplanner是一种基于格的路径规划算法,可以在杂的环境中进行高效的路径规划。本攻略将介绍latticeplanner的基本原理和使用方法。 步骤一:装latticeplanner 首先,需要在本地计算…

    other 2023年5月10日
    00
  • .net反编译的九款神器

    .NET反编译是一种将已编译的.NET程序集转换回其源代码的过程。这种技术可以帮助开发人员理解和修改现有的.NET程序集。以下是.NET编译的九款神器的完整攻略: dnSpy dnSpy是一免费的.NET反编译器,可以反编译.NET程序集并查看其源代码。它还支持调试反编译的代码,并提供了一些其他有用的功能,如查看程序集的元数据和IL代码。以下是使用dnSpy…

    other 2023年5月7日
    00
  • KMP算法最浅显理解(小白教程)

    KMP算法最浅显理解(小白教程) 什么是KMP算法? KMP算法(Knuth-Morris-Pratt算法)是一种字符串匹配算法,用于在一个主串中查找一个模式串的出现位置。与朴素的字符串匹配算法相比,KMP算法具有更高的效率。 KMP算法的基本思想 KMP算法的基本思想是利用已经匹配过的部分信息,避免不必要的回溯。它通过构建一个部分匹配表(Partial M…

    other 2023年8月6日
    00
  • 微信开发者工具怎么更改语言 微信开发者工具更改语言教程

    下面是关于“微信开发者工具怎么更改语言”的完整攻略。 1. 打开微信开发者工具 打开微信开发者工具,进入任意小程序的开发页面。 2. 进入设置页面 点击工具栏中的“设置”按钮,或者使用快捷键“Ctrl + ,”,打开微信开发者工具的设置页面。 3. 进入语言设置页面 在设置页面中,点击“用户界面”选项卡,下拉找到“语言”一项,点击“语言”右边的下拉菜单,在里…

    other 2023年6月26日
    00
  • java中重写父类方法加不加@Override详解

    在Java中,当子类要重写父类的方法时,需要注意是否添加@Override注解。这个注解的作用是告诉编译器,这是一种重写父类方法的声明。在某些情况下,我们必须使用此注解。下面来具体看看。 为什么要使用@Override注解? 防止错误 首先,为了避免在代码中出现错误,Java中的子类重写父类方法时必须使用@Override注解。如果在方法的声明中省略了此注解…

    other 2023年6月26日
    00
  • java 抽象类的实例详解

    Java 抽象类的实例详解 什么是抽象类? 抽象类是一种不能实例化的类,它为其他类提供了一种通用的抽象概念。抽象类可以包含抽象方法和非抽象方法。抽象方法只有方法名,没有具体的实现,而非抽象方法有具体的实现。 抽象类通过关键字abstract来声明。抽象方法必须在抽象类中声明,而非抽象方法不一定要在抽象类中声明。 抽象类的定义与实现 定义抽象类的基本语法为: …

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部