Tipo de dados par / tupla em Go

118

Enquanto fazia o exercício final do Tour of Go , decidi que precisava de uma fila de ( string, int) pares. Isso é bastante fácil:

type job struct {
    url string
    depth int
}

queue := make(chan job)
queue <- job{url, depth}

Mas isso me fez pensar: existem tipos de dados par / tupla integrados no Go? Há suporte para retornar vários valores de uma função, mas AFAICT, as múltiplas tuplas de valor produzidas não são cidadãos de primeira classe no sistema de tipos de Go. É esse o caso?

Quanto à parte "o que você tentou", a sintaxe óbvia (do ponto de vista de um programador Python)

queue := make(chan (string, int))

não funcionou.

Fred Foo
fonte

Respostas:

57

Não há tipo de tupla em Go, e você está correto, os múltiplos valores retornados por funções não representam um objeto de primeira classe.

A resposta de Nick mostra como você pode fazer algo semelhante que lida com tipos arbitrários usando interface{}. (Eu poderia ter usado uma matriz em vez de uma estrutura para torná-la indexável como uma tupla, mas a ideia principal é o interface{}tipo)

Minha outra resposta mostra como você pode fazer algo semelhante que evita a criação de um tipo usando estruturas anônimas.

Essas técnicas têm algumas propriedades de tuplas, mas não, não são tuplas.

Sonia
fonte
91

Você consegue fazer isso. Parece mais prolixo do que uma tupla, mas é uma grande melhoria porque você obtém verificação de tipo.

Editar: trecho substituído com exemplo de trabalho completo, seguindo a sugestão de Nick. Link do Playground: http://play.golang.org/p/RNx_otTFpk

package main

import "fmt"

func main() {
    queue := make(chan struct {string; int})
    go sendPair(queue)
    pair := <-queue
    fmt.Println(pair.string, pair.int)
}

func sendPair(queue chan struct {string; int}) {
    queue <- struct {string; int}{"http:...", 3}
}

Structs e campos anônimos são adequados para soluções rápidas e sujas como esta. Para todos os casos, exceto os mais simples, porém, você faria melhor definir uma estrutura nomeada como fez.

Sonia
fonte
9
Você provavelmente deve descrever como obter os valores dos membros de struct anônimos porque não acho que seja óbvio para um iniciante!
Nick Craig-Wood
9
no entanto, isso não funcionará se houver vários campos com o mesmo tipo
newacct
1
Você pode ter campos nomeados em uma estrutura anônima, você só precisa ter certeza de que os campos são nomeados da mesma forma que em cada lugar a definição da estrutura anônima aparece (três vezes neste exemplo). Os campos anônimos são mais fáceis se você puder fazer isso .
Sonia
5
Portanto, a resposta é "não, não há tipo de tupla"?
Fred Foo
37

Você poderia fazer algo assim se quisesse

package main

import "fmt"

type Pair struct {
    a, b interface{}
}

func main() {
    p1 := Pair{"finished", 42}
    p2 := Pair{6.1, "hello"}
    fmt.Println("p1=", p1, "p2=", p2)
    fmt.Println("p1.b", p1.b)
    // But to use the values you'll need a type assertion
    s := p1.a.(string) + " now"
    fmt.Println("p1.a", s)
}

No entanto, acho que o que você já tem é perfeitamente idiomático e a estrutura descreve seus dados perfeitamente, o que é uma grande vantagem sobre o uso de tuplas simples.

Nick Craig-Wood
fonte