How to make a channel that receive multiple return values from a goroutine

Go

Go Problem Overview


I have a function in Go that returns two values. I want to run this as a goroutine, but I can't figure out the syntax for creating a channel that receives two values. Could someone point me in the right direction?

Go Solutions


Solution 1 - Go

Define a custom type with fields for both values, then create a chan of that type.

EDIT: I've also added an example (right at the bottom) that uses multiple channels rather than a custom type. I'm not sure which is more idiomatic.

For example:

type Result struct {
    Field1 string
    Field2 int
}

then

ch := make(chan Result)

Example of using a channel of a custom type (Playground):

package main

import (
	"fmt"
	"strings"
)

type Result struct {
	allCaps string
	length  int
}

func capsAndLen(words []string, c chan Result) {
	defer close(c)
	for _, word := range words {
		res := new(Result)
		res.allCaps = strings.ToUpper(word)
		res.length = len(word)
		c <- *res		
	}
}

func main() {
	words := []string{"lorem", "ipsum", "dolor", "sit", "amet"}
	c := make(chan Result)
	go capsAndLen(words, c)
	for res := range c {
		fmt.Println(res.allCaps, ",", res.length)
	}
}

Produces: >LOREM , 5
IPSUM , 5
DOLOR , 5
SIT , 3
AMET , 4

EDIT: Example using multiple channels instead of a custom type to produce the same output (Playground):

package main

import (
	"fmt"
	"strings"
)

func capsAndLen(words []string, cs chan string, ci chan int) {
	defer close(cs)
	defer close(ci)
	for _, word := range words {
		cs <- strings.ToUpper(word)
		ci <- len(word)
	}
}

func main() {
	words := []string{"lorem", "ipsum", "dolor", "sit", "amet"}
	cs := make(chan string)
	ci := make(chan int)
	go capsAndLen(words, cs, ci)
	for allCaps := range cs {
		length := <-ci
		fmt.Println(allCaps, ",", length)
	}
}

Solution 2 - Go

Another option would be to use an anon function like so:

package main

import "fmt"

func f(c chan func() (int, string)) {
	c <- (func() (int, string) { return 0, "s" })
}

func main() {
	c := make(chan func() (int, string))
	go f(c)
	y, z := (<-c)()
	fmt.Println(y)
	fmt.Println(z)
}

Credit to https://gist.github.com/slav/ca2ee333c29b8f76b557c9b10b371b52

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
QuestionSam LeeView Question on Stackoverflow
Solution 1 - GoIntermernetView Answer on Stackoverflow
Solution 2 - GopwaterzView Answer on Stackoverflow