5

Go 语言泛型简介与应用

 1 year ago
source link: https://www.fdevops.com/2023/04/10/31273
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Go 语言泛型简介与应用

兰玉磊 • 18小时前 • 其他 • 阅读 21

Go 语言自 1.18 版本开始引入了泛型支持,使得开发者可以使用更加灵活且类型安全的代码。泛型提供了编写通用、可重用的代码的能力,减少了重复的代码,使得程序更加简洁。本文将详细介绍 Go 语言泛型的基本概念和使用场景,并附有示例代码。

泛型基本概念

泛型,顾名思义,是指通用类型。在编程语言中,泛型的概念就是允许在函数或数据结构中定义类型参数,使得函数或数据结构可以处理多种类型的数据。这样,我们可以针对不同类型的数据实现相同的操作,减少重复代码。

类型参数是泛型中的核心概念。在 Go 语言中,使用 type 关键字定义类型参数。类型参数列表位于函数名或结构体名后面,用方括号 [] 包围,类型参数之间用逗号 , 分隔。如下所示:

func PrintSlice[T any](s []T) {
   // ...
}

在这个例子中,T 是一个类型参数,any 表示 T 可以是任何类型。这个函数接受一个类型为 T 的切片,并对其进行打印操作。

类型约束是用来限制类型参数的取值范围。在 Go 语言中,使用接口作为类型约束。例如,我们可以定义一个只接受实现了 Stringer 接口的类型参数的泛型函数:

type Stringer interface {
   String() string
}

func PrintString[T Stringer](s T) {
   fmt.Println(s.String())
}

在这个例子中,类型参数 T 必须实现 Stringer 接口,否则编译器会报错。

下面我们来看一些使用 Go 语言泛型的例子。

泛型切片反转

我们来实现一个泛型版本的切片反转函数:

package main

import "fmt"

func Reverse[T any](s []T) []T {
  length := len(s)
  result := make([]T, length)
  for i := 0; i < length; i++ {
      result[length-1-i] = s[i]
  }
  return result
}

func main() {
  intSlice := []int{1, 2, 3, 4, 5}
  reversedIntSlice := Reverse(intSlice)
  fmt.Println(reversedIntSlice) // Output: [5 4 3 2 1]

  strSlice := []string{"A", "B", "C", "D"}
  reversedStrSlice := Reverse(strSlice)
  fmt.Println(reversedStrSlice) // Output: [D C B A]

floatSlice := []float64{1.1, 2.2, 3.3, 4.4}
  reversedFloatSlice := Reverse(floatSlice)
  fmt.Println(reversedFloatSlice) // Output: [4.4 3.3 2.2 1.1]
}

在这个示例中,我们定义了一个泛型函数 Reverse,它接受一个类型为 T 的切片,并返回一个新的反转后的切片。我们分别对整数切片、字符串切片和浮点数切片进行了反转操作,展示了泛型函数的通用性。

泛型映射函数

接下来,我们实现一个泛型的映射函数,它接受一个类型为 T 的切片和一个将 T 类型转换为 U 类型的函数,然后返回一个类型为 U 的切片:

package main

import "fmt"

func Map[T, U any](s []T, f func(T) U) []U {
  length := len(s)
  result := make([]U, length)
  for i, v := range s {
      result[i] = f(v)
  }
  return result
}

func main() {
  intSlice := []int{1, 2, 3, 4, 5}
  toString := func(i int) string {
      return fmt.Sprintf("%d", i)
  }
  strSlice := Map(intSlice, toString)
  fmt.Println(strSlice) // Output: [1 2 3 4 5]

  strSlice2 := []string{"apple", "banana", "cherry"}
  toLength := func(s string) int {
      return len(s)
  }
  intSlice2 := Map(strSlice2, toLength)
  fmt.Println(intSlice2) // Output: [5 6 6]
}

在这个示例中,我们定义了一个泛型函数 Map,它接受一个类型为 T 的切片和一个将 T 类型转换为 U 类型的函数。然后返回一个类型为 U 的切片。我们分别使用整数切片和字符串切片进行了映射操作,展示了泛型函数的灵活性。

Go 语言泛型为我们提供了一个强大的工具,使得我们能够编写更加通用、可重用的代码,同时保持类型安全性。本文详细介绍了 Go 语言泛型的基本概念和使用场景,并通过实际示例展示了泛型的应用。希望对你有所帮助,祝你在 Go 语言编程中愉快地使用泛型!

本文为原创文章,未经授权禁止转载本站文章。
原文出处:兰玉磊的个人博客
原文链接:https://www.fdevops.com/2023/04/10/31273
版权:本文采用「署名-非商业性使用-相同方式共享 4.0 国际」知识共享许可协议进行许可。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK