Una breve introducción a los genéricos en Go

¡Acostúmbrate a escribir juntos! Este es el día 11 de mi participación en el "Nuevo plan diario de Nuggets · Desafío de actualización de abril", haga clic para ver los detalles del evento .

Genéricos

Amigos que están familiarizados con Java, todos entienden 泛型el uso. De hecho, no tengo muy claro el papel de los genéricos, probablemente porque Python no es un lenguaje fuertemente tipado. Entonces, en esta sección, planeo hablar sobre el interior de go según mi propio entendimiento 泛型.

¿Por qué necesita genéricos?

He comprobado alguna información sobre esta pregunta, echemos un vistazo a la respuesta dada por StackOverFlow:

Cuando no usamos genéricos (se parece un poco a una lista en Python), aunque podemos agregar cualquier elemento a la lista, necesitamos 显式convertir el tipo cuando lo sacamos, porque:

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

En go es así:

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

De hecho, si queremos escribir un método genérico para obtener el primer elemento de la matriz 索引, ¿qué debemos hacer si no hay un tipo genérico?

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

Nuestra suposición inicial puede ser esta, pasar cualquier []interfaz{} y juzgar si los dos son iguales a través de la reflexión, pero de hecho esto no funciona, porque no []intse puede usar como []interface{}parámetro. (Oye, no me lo esperaba)

Entonces solo podemos hacerlo de otra manera:

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
}
复制代码

Se puede ver que ahora solo estoy apuntando a matrices en formato int, no solo hago matrices 类型转化, sino también conversiones de tipo de elemento, y soy perezoso y no he escrito la suma de verificación de tipo de ele int32, float32, float64, string, etc. A la espera de muchos otros tipos de conversiones, esto es realmente doloroso. Personalmente siento que esto es realmente inconveniente.

Entra en el mundo de los genéricos

Pensé que go admitiría oficialmente genéricos en 2.x, pero luego descubrí que la versión beta de 1.18 ya admite básicamente genéricos. Hace algún tiempo, el blogger descubrió en el sitio web oficial de go que go1.18 se había lanzado oficialmente, por lo que lo descargó para probarlo. Sin embargo, en la actualidad, el editor de Goland tendrá algunos errores cuando encuentre genéricos, esto solo se puede esperar de la versión de Goland 2022.1.

Escribir métodos genéricos

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)
}

复制代码

看看执行结果:

Imagen de WeChat_20220411222937.png

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


En resumen, el papel de los genéricos sigue siendo bastante grande. Intenté escribir []interfaz{} y me di cuenta de lo incómodo que es no tener genéricos. La cama de imágenes de mdnice está un poco estirada (la resolución es enorme), ¡y planeo cambiar el editor más tarde! ! ! El contenido de hoy se comparte aquí, ¡el hígado japonés es demasiado incómodo! !

Supongo que te gusta

Origin juejin.im/post/7085353484354060302
Recomendado
Clasificación