Une brève introduction aux génériques en Go

Prenez l'habitude d'écrire ensemble ! C'est le 11ème jour de ma participation au "Nuggets Daily New Plan · April Update Challenge", cliquez pour voir les détails de l'événement .

Génériques

Amis qui connaissent Java, tous comprennent 泛型l'utilisation. En fait, je ne suis pas très clair sur le rôle des génériques, probablement parce que Python n'est pas un langage fortement typé. Donc, dans cette section, je prévois de parler de l'intérieur du go en me basant sur ma propre compréhension 泛型.

Pourquoi avez-vous besoin de génériques

J'ai vérifié quelques informations sur cette question, regardons la réponse donnée par StackOverFlow :

Lorsque nous n'utilisons pas de génériques (cela ressemble un peu à une liste en Python), bien que nous puissions ajouter n'importe quel élément à la liste, nous devons 显式convertir le type lorsque nous le retirons, car :

List list = new ArrayList(); // 数组里面存放的是Object对象
复制代码

En go c'est comme ça :

// 初始化一个存放任意类型的数组,这里的interface{} 代表任意类型
var list = make([]interface{}, 0)
复制代码

En effet, si on veut écrire une méthode générique pour récupérer le premier élément du tableau 索引, que faut-il faire s'il n'y a pas de type générique ?

func getIndex(data []interface{}, ele interface{}) int {
	for i, item := range data {
		if reflect.DeepEqual(item, ele) {
			return i
		}
	}
	return -1
}
复制代码

Notre hypothèse initiale peut être ceci, passer dans n'importe quelle []interface{}, et juger si les deux sont égaux par réflexion, mais en fait cela ne fonctionne pas, car il []intne peut pas être utilisé comme []interface{}paramètre. (Hé, je ne m'y attendais pas)

Ensuite, nous ne pouvons le faire que d'une autre manière:

func getIndex(data interface{}, ele interface{}) int {
	switch data.(type) {
	case []int:
		result := data.([]int)
		for i, item := range result {
			if item == ele.(int) {
				return i
			}
		}
		return -1
	}
	return -1
}
复制代码

On peut voir que je ne cible que les tableaux au format int maintenant, non seulement les tableaux 类型转化, mais aussi les conversions de type d'élément, et je suis paresseux et je n'ai pas écrit la somme de contrôle de type de ele int32, float32, float64, string, etc. En attendant de nombreux autres types de conversions, c'est vraiment douloureux. Personnellement, je pense que c'est vraiment gênant.

Entrez dans le monde des génériques

Je pensais que go prendrait officiellement en charge les génériques dans 2.x, mais j'ai découvert plus tard que la version bêta de 1.18 prend déjà en charge les génériques. Il y a quelque temps, le blogueur a découvert sur le site officiel de go que go1.18 était officiellement sorti, alors il l'a téléchargé pour l'essayer. Cependant, à l'heure actuelle, l'éditeur Goland aura quelques bugs lorsqu'il rencontrera des génériques, ce qui ne peut être attendu qu'à partir de la version Goland 2022.1.

Ecrire des méthodes génériques

go里面能用到泛型的地方有好几处,我们今天就只讲讲简单点的,运用于方法和接口上的泛型。先来看看定义在方法上的泛型,我们来改造刚才的例子:

func findIndex[T comparable](data []T, ele T) int {
	for i, item := range data {
		if item == ele {
			return i
		}
	}
	return -1
}
复制代码

我们可以看到,在函数名和参数之间多了个[T comparable]的语句,这个的意思是,声明这个方法接收的类型为comparable,并定义为T,接着参数为T(comparable)的数组,和T。

有的同学要问了,为啥不是:

func findIndex(data []comparable, ele comparable) int {
	for i, item := range data {
		if item == ele {
			return i
		}
	}
	return -1
}
复制代码

问的很好,首先这样会与我们上面写的demo一样,[]int不为[]comparable类型,其次,这里的T,也可以看做一个变量,我的理解是这样的,我们以往定义的方法,参数都是固定的,现在我想让参数的类型也能随心所欲地变化。但是这个变化又有个度,不是所有类型都可以,所以我界定了一个T类型,也就是comparable,可比较的(comparable是go原生的方法,int,float等类型都默认实现了这个接口)。所以你传int的时候,我发现是可比较的,这时候T就等于int,传入float32的时候,T这时候就是float32。所以我个人感觉,可以把T当做变化的类型

编写泛型接口

泛型接口比较简单了,简单的说就算是类型的结合,比如我这个方法,获取索引,我只想要支持string,float和int,其他的我都不支持。

type MyType interface {
  int | float32 | string
}
复制代码

有人说,我的time.Duration这种呢?是属于int64的扩展类型:

如果也要支持这种的话,我们在类型前面加上~即可:

type MyType interface {
  int | float32 | string | ~int64
}
复制代码

这样既可以支持int64,也可以支持time.Duration这种扩展类型。

二者结合

我们刚才改造的例子,传入的参数我们要从comparable改为MyType,看一个完整的例子:

package main

import "fmt"

type MyType interface {
	~int | ~float32 | ~int64 | string
}

func findIndex[T MyType](data []T, ele T) int {
	for i, item := range data {
		if item == ele {
			return i
		}
	}
	return -1
}

func main() {
	arr1 := []int{2, 3, 4, 5, 6}
	arr2 := []string{"李逍遥", "吴敬梓", "头铁娃", "陈玄风", "巴基斯坦"}
	four := findIndex(arr1, 4)
	iron := findIndex(arr2, "头铁娃")
	fmt.Println("4的索引是", four)
	fmt.Println("头铁娃的索引是", iron)
}

复制代码

看看执行结果:

Image WeChat_20220411222937.png

我们测试下换个我们没有的类型: uint


En résumé, le rôle des génériques est encore assez important. Je viens d'essayer d'écrire []interface{}, et je viens de réaliser à quel point il est inconfortable de ne pas avoir de génériques. Le lit d'image de mdnice est un peu étiré (la résolution est énorme), et je prévois de changer d'éditeur plus tard ! ! ! Le contenu d'aujourd'hui est partagé ici, le foie japonais est trop inconfortable ! !

Je suppose que tu aimes

Origine juejin.im/post/7085353484354060302
conseillé
Classement