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

type job struct {url stringdepth 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 as far as I can tell, 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.

6

Best Answer


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 mainimport "fmt"func main() {queue := make(chan struct {string; int})go sendPair(queue)pair := <-queuefmt.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.

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.

You could do something like this if you wanted

package mainimport "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 assertions := 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.

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 {First TSecond U}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).

type Pair struct {

values [2]interface{}

}

func MakePair(k, v interface{}) Pair {

return Pair{values:[2]interface{}{k, v}}

}

func (p Pair) Get(i int) interface{} {

return p.values[i]

}

func main() {

p := MakePair("Hello", false)fmt.Println(p.Get(0), " ", p.Get(1))

}

There are no built-in tuples/pairs in Go. I had the exact same issue with you, so I created this simple package, so I don't need to reinvent the wheel in my every project:

Go Pair package