От издание 1.18 насам Го поддържа обобщения1, познати още като податки за вид2.
import "fmt"
SlicesIndex е пример за обобщена функция. Приема отрязък от всеки сравним (comparable) вид данни и един член от такъв вид, и връща показалец към първото съвпадение с v в s, или -1, ако не го намери.
Ограничението1 comparable (сравним)
означава, че можем да сравняваме данните от такъв вид
чрез действията2 == и !=. Много по-задълбочено обяснение ще намерите в тази статия.
Обърнете внимание, че тази функция съществува в
стандартната библиотека под името
slices.Index.
func SlicesIndex[S ~[]E, E comparable](s S, v E) int {
for i := range s {
if v == s[i] {
return i
}
}
return -1
}
Ето един примерен обобщен вид. List е единично
свързан списък, който може да съдържа стойности от
всякакъв1 вид.
interface{}, което в Го означава данна от всякакъв вид.type List[T any] struct {
head, tail *element[T]
}
type element[T any] struct {
next *element[T]
val T
}
Можем да създаваме методи за обобщени видове, но трябва
да обявяваме податките за вида. Вида е List[T], не
List.
func (lst *List[T]) Push(v T) {
if lst.tail == nil {
lst.head = &element[T]{val: v}
lst.tail = lst.head
} else {
lst.tail.next = &element[T]{val: v}
lst.tail = lst.tail.next
}
}
AllElements връща всички членове на List като
отрязък. В следващия пример ще видим
по-изразителен1 начин да обикаляме по
членовете на потребителски2 видове.
func (lst *List[T]) AllElements() []T {
var elems []T
for e := lst.head; e != nil; e = e.next {
elems = append(elems, e.val)
}
return elems
}
func main() {
var s = []string{"ала", "бала", "ница"}
Когато извикваме обобщени функции, често можем да
разчитаме, че Го ще отгатне1 вида.
Забележете, че не е нужно да указваме вида на S и
E, когато извикваме SlicesIndex. Компилаторът
отгатва вида им сам.
fmt.Printf("на кое място е %q: %d\n",
s[0], SlicesIndex(s, "ала"))
… макар че бихме могли да ги зададем и изрично.
_ = SlicesIndex[[]string, string](s, "zoo")
lst := List[int]{}
lst.Push(10)
lst.Push(13)
lst.Push(23)
fmt.Println("списък:", lst.AllElements())
}
$ go run ./generics.go
на кое място е "ала": 0
списък: [10 13 23]
Следващ пример: Обхождане чрез повторители.