Generics был выпущен с версией Go 1.18. В основном это означает параметризованные типы, что означает, что он позволяет программистам писать код, в котором тип может быть указан позже, потому что тип в этот момент не имеет значения. Другими словами, при написании кода вы не указываете тип значений. Эти значения типа передаются позже.
Его синтаксис:
func funcName[type_parameter type_constraint](… type_parameter) type_parameter { … } func funcName[T any](… T) T { … } func funcName[T interface{}](… T) T { … }
Здесь T — это параметр типа, а any — это ограничение типа, которое может быть любым интерфейсом, означает неограниченные значения, здесь any представляет собой пустой интерфейс.
В приведенном ниже примере есть две функции, первая returnFirst принимает любое ограничение, что означает, что мы можем передать что-либо, не являющееся конкретным int или float, и она возвращает первый аргумент. Вторая функция, а именно returnFloatFirst, принимает в качестве аргумента только тип float64, и если мы передадим любой другой тип, она выдаст ошибку. В основной функции вы можете видеть, что функцию returnFirst мы можем вызывать без указания типа ограничения, и она работает, это связано с выводом типа.
func returnFirst[T any](a T, b T) T { return a } func returnFloatFirst[T float64](a T, b T) T { return a } func main() { fmt.Println(returnFirst[int](1,3)) fmt.Println(returnFirst(1,3)) fmt.Println(returnFirst[float64](1.8,3.9)) fmt.Println(returnFirst(1.8,3.9)) fmt.Println(returnFirst("a","b")) fmt.Println(returnFloatFirst(1.2,3.4)) }
Go 1.18 поставляется с выводом типов, который помогает нам писать код, вызывающий универсальные функции без явных типов.
Давайте возьмем другой пример, скажем, вам нужно вычислить сумму всех элементов массива, теперь, если я скажу, что каждый раз, когда я меняю тип данных, хранящихся в массиве, тогда реализация функции останется прежней, но вы должны напишите отдельную функцию для разных типов, поэтому давайте напишем общую функцию, которая складывает элементы массива и возвращает сумму.
func sumAll[T any](arr []T) T { var s T for _, ele := range arr { s += ele } return s } func main() { fmt.Println("sum: ", sumAll([]int{1, 2, 3, 5, 6})) }
Когда вы запустите приведенный выше код, он выдаст ошибку:
$ go run main.go ./main.go:6:9: invalid operation: operator + not defined on a (variable of type T constrained by any)
Это связано с тем, что любое ограничение может содержать любое значение, здесь, в приведенном выше случае, это int, но это может быть что угодно, и есть вероятность, что оператор может не работать для этого конкретного типа. поэтому выдает ошибку. Чтобы решить эту проблему, мы используем набор типов, где мы определяем пользовательское ограничение с помощью интерфейса и используем его вместо ограничения типа. Мы объявляем набор типов для этого ограничения и должны использовать только эти типы.
Синтаксис для определения пользовательского ограничения:
type customConstraint interface { type1 | type2 | type3 … } type cusConstraint interface { float64 | int | string }
Мы также можем использовать пакет constraints, который определяет набор полезных ограничений, которые будут использоваться с параметрами
Сначала мы должны установить пакет ограничений.
$ go get golang.org/x/exp/constraints
Некоторые ограничения из пакета.
type Signed interface { ~int | ~int8 | ~int16 | ~int32 | ~int64 } type Unsigned interface { ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr } type Integer interface { Signed | Unsigned } type Float interface { ~float32 | ~float64 } type Complex interface { ~complex64 | ~complex128 } type Ordered interface { Integer | Float | ~string }
Итак, теперь давайте создадим пользовательское ограничение, которое может поддерживать типы данных float64 и int, и используем его вместо любого ограничения.
type constraint interface { ~float64 | int } func sumAll[T constraint](arr []T) T { var s T for _, ele := range arr { s += ele } return s } func main() { fmt.Println("sum: ", sumAll([]int{1, 2, 3, 5, 6})) fmt.Println("sum: ", sumAll([]float64{1.2, 2.1, 3.8, 5.4})) }
Приведенный выше код работает.
Спасибо, что написали эту часть, пожалуйста, добавьте свои ценные комментарии и предложения, чтобы я мог сделать статью более интерактивной.