comparable în Go

Constrângere predefinită pentru generics: tipurile care se pot compara cu == și != (pot fi chei de map).

Sintaxă
func Index[T comparable](s []T, v T) int
type Multime[T comparable] map[T]struct{}

Ce face comparable

comparable este o interfață predefinită pe care o îndeplinesc toate tipurile ce se pot compara cu == și !=: bool, numere, texte, pointeri, canale, array-uri și struct-uri formate din tipuri comparabile, precum și interfețele. Slice-urile, map-urile și funcțiile nu sunt comparabile.

Se poate folosi doar ca constrângere pentru parametri de tip, nu ca tip de variabilă. O folosești când funcția sau tipul generic compară valori sau le pune drept chei într-un map: slices.Index, slices.Contains și maps cer comparable.

Pentru interfețe, comparația poate da panic la rulare dacă valorile concrete din ele nu sunt comparabile (de exemplu două any care țin slice-uri).

Exemple

Exemplul 1: Căutare generică și mulțime

package main

import "fmt"

func Index[T comparable](s []T, v T) int {
    for i, x := range s {
        if x == v {
            return i
        }
    }
    return -1
}

type Multime[T comparable] map[T]struct{}

func (m Multime[T]) Adauga(v T)       { m[v] = struct{}{} }
func (m Multime[T]) Contine(v T) bool { _, ok := m[v]; return ok }

func main() {
    fmt.Println(Index([]string{"Iași", "Cluj", "Arad"}, "Cluj"))
    fmt.Println(Index([]float64{1.5, 2.5}, 9))

    vizitate := Multime[string]{}
    vizitate.Adauga("Sibiu")
    vizitate.Adauga("Sibiu")
    fmt.Println(len(vizitate), vizitate.Contine("Sibiu"), vizitate.Contine("Iași"))
}

Rezultat

1
-1
1 true false

Exemplul 2: Struct-uri comparabile ca chei

Punct are doar câmpuri comparabile, deci îndeplinește comparable.

package main

import "fmt"

type Punct struct{ X, Y int }

func Numara[T comparable](valori []T) map[T]int {
    m := map[T]int{}
    for _, v := range valori {
        m[v]++
    }
    return m
}

func main() {
    clicuri := []Punct{{1, 2}, {3, 4}, {1, 2}, {1, 2}}
    fmt.Println(Numara(clicuri))
}

Rezultat

map[{1 2}:3 {3 4}:1]

Greșeli frecvente

  • var x comparable: cannot use type comparable outside a type constraint: interface is (or embeds) comparable.
  • Index([][]int{...}, ...): []int does not satisfy comparable.
  • [T any] în loc de [T comparable] când folosești ==: invalid operation: a == b (incomparable types in type set).

Comenzi înrudite

  • generics (parametri de tip): Funcții și tipuri care lucrează cu mai multe tipuri, scrise o singură dată cu parametri de tip [T constrângere].
  • any: Alias pentru interface{}: un tip care poate ține orice valoare; folosit și drept constrângere în generics.
  • map și map-uri: Tabel cheie-valoare (dicționar): căutare rapidă după cheie, adăugare, ștergere și verificare cu v, ok.
  • interface și interfețe: Interfața descrie un set de metode; orice tip care le are o implementează automat, fără declarație explicită.