Pair/tuple data type in Go

GoTuples

Go Problem Overview


I need a queue of (string, int) pairs. That's easy enough:

type job struct {
    url string
    depth int
}

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

are there built-in pair/tuple data types in Go? There is support for returning multiple values from a function, but AFAICT, the multiple value tuples produced are not first-class citizens in Go's type system. Is that the case?

As for the "what have you tried" part, the obvious syntax (from a Python programmer's POV)

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

didn't work.

Go Solutions


Solution 1 - Go

You can do this. It looks more wordy than a tuple, but it's a big improvement because you get type checking.

Edit: Replaced snippet with complete working example, following Nick's suggestion. Playground link: 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}
}

Anonymous structs and fields are fine for quick and dirty solutions like this. For all but the simplest cases though, you'd do better to define a named struct just like you did.

Solution 2 - Go

There is no tuple type in Go, and you are correct, the multiple values returned by functions do not represent a first-class object.

Nick's answer shows how you can do something similar that handles arbitrary types using interface{}. (I might have used an array rather than a struct to make it indexable like a tuple, but the key idea is the interface{} type)

My other answer shows how you can do something similar that avoids creating a type using anonymous structs.

These techniques have some properties of tuples, but no, they are not tuples.

Solution 3 - Go

You could do something like this if you wanted

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

However I think what you have already is perfectly idiomatic and the struct describes your data perfectly which is a big advantage over using plain tuples.

Solution 4 - Go

Go 1.18 (estimated to be released February 2022) will add support for generics.

This will make it very easy to declare tuple types:

type Pair[T, U any] struct{
    T First
    U Second
}

func main() {
    queue := make(chan Pair[string, int])
}

You can try it with the beta right now!

You can also use a library for generic tuples like the one I wrote (go-tuple).

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionFred FooView Question on Stackoverflow
Solution 1 - GoSoniaView Answer on Stackoverflow
Solution 2 - GoSoniaView Answer on Stackoverflow
Solution 3 - GoNick Craig-WoodView Answer on Stackoverflow
Solution 4 - GoBar WeissView Answer on Stackoverflow