Type de données paire / tuple dans Go

118

Lors de l' exercice final du Tour of Go , j'ai décidé que j'avais besoin d'une file d'attente de ( string, int) paires. C'est assez simple:

type job struct {
    url string
    depth int
}

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

Mais cela m'a fait réfléchir: existe-t-il des types de données paire / tuple intégrés dans Go? Il existe un support pour renvoyer plusieurs valeurs à partir d'une fonction, mais AFAICT, les tuples de valeurs multiples produits ne sont pas des citoyens de première classe dans le système de type de Go. Est-ce le cas?

Quant à la partie "qu'as-tu essayé", la syntaxe évidente (du POV d'un programmeur Python)

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

n'a pas fonctionné.

Fred Foo
la source

Réponses:

57

Il n'y a pas de type tuple dans Go, et vous avez raison, les valeurs multiples renvoyées par les fonctions ne représentent pas un objet de première classe.

La réponse de Nick montre comment vous pouvez faire quelque chose de similaire qui gère les types arbitraires en utilisant interface{}. (J'aurais peut-être utilisé un tableau plutôt qu'une structure pour le rendre indexable comme un tuple, mais l'idée clé est le interface{}type)

Mon autre réponse montre comment vous pouvez faire quelque chose de similaire qui évite de créer un type à l'aide de structures anonymes.

Ces techniques ont certaines propriétés des tuples, mais non, ce ne sont pas des tuples.

Sonia
la source
91

Tu peux le faire. Cela semble plus verbeux qu'un tuple, mais c'est une grande amélioration car vous obtenez une vérification de type.

Edit: extrait de code remplacé par un exemple de travail complet, suite à la suggestion de Nick. Lien 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}
}

Les structures et les champs anonymes conviennent parfaitement aux solutions rapides et sales comme celle-ci. Pour tous les cas sauf les plus simples, vous feriez mieux de définir une structure nommée comme vous l'avez fait.

Sonia
la source
9
Vous devriez probablement décrire comment extraire les valeurs des membres anonymes de la structure car je ne pense pas que ce soit évident pour un débutant!
Nick Craig-Wood
9
cependant, cela ne fonctionnera pas s'il y a plusieurs champs avec le même type
newacct
1
Vous pouvez avoir des champs nommés dans une structure anonyme, il vous suffit de vous assurer que les champs sont nommés de la même manière à chaque endroit où la définition de structure anonyme apparaît (trois fois dans cet exemple.) Les champs anonymes sont plus faciles si vous pouvez vous en tirer. .
Sonia
5
Donc la réponse est "non, il n'y a pas de type tuple"?
Fred Foo
37

Tu pourrais faire quelque chose comme ça si tu voulais

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

Cependant, je pense que ce que vous avez déjà est parfaitement idiomatique et la structure décrit parfaitement vos données, ce qui est un gros avantage par rapport à l'utilisation de tuples simples.

Nick Craig-Wood
la source