Create chan for func with two return args

Issue

Is it posible to create channel for function boolInt without redefining it?

package main

func boolInt() (bool, int) {
    return false, 1
}

func main() {
    chanBool := make(chan bool)
    chanInt := make(chan int)
    go func() {
        // chanBool <- boolInt() // error: multiple-value boolInt() in single-value context
        chanBool, chanInt <- boolInt() //  syntax error: unexpected semicolon or newline, expecting := or = or comma
    }()

}

When I try to use it in single value context
chanBool <- boolInt() I get an error: multiple-value boolInt() in single-value context.

In 2-value context:
chanBool, chanInt <- boolInt() got error: syntax error: unexpected semicolon or newline, expecting := or = or comma.

playground

Solution

Using 2 different channels

You want to send values to 2 different channels. Sending a value to a channel is not an assignment, so you can’t send on both channels in one step.

First store the values returned by boolInt(), then send the values to the 2 channels like this:

go func() {
    b, i := boolInt()
    chanBool <- b
    chanInt <- i
}()

Testing it:

go func() {
    b, i := boolInt()
    chanBool <- b
    chanInt <- i
}()

fmt.Println("Received bool:", <-chanBool)
fmt.Println("Received int:", <-chanInt)

Output:

Received bool: false
Received int: 1

Note: you first have to receive from chanBool because you created unbuffered channels, and because in the example we first send to chanBool, that blocks until the sent value is recevied and only then proceeds to send a value to the chanInt. Attempting to receive from chanInt first would cause a deadlock ("fatal error: all goroutines are asleep - deadlock!").

Solution using only one channel

If you want to send multiple values on a channel, you can create a wrapper struct for the values:

type MyStruct struct {
    b bool
    i int
}

And using it:

ch := make(chan MyStruct)
go func() {
    b, i := boolInt()
    ch <- MyStruct{b, i}
}()

fmt.Println("Received value:", <-ch)

Output:

Received value: {false 1}

Note: You could also use a []interface{} slice as a wrapper, but a struct provides a clearer way and type safety to its fields.

Note #2: It would make things easier and clearer if the boolInt() function itself would return a MyStruct value:

func boolInt() MyStruct {
    return MyStruct{false, 1}
}

In which case code would be as simple as this:

ch := make(chan MyStruct)
go func() {
    ch <- boolInt()
}()

Alternative 1 channel solution

Another option is to make the channel type interface{} so it can receive values of any type, and just send/receive multiple values on it:

ch := make(chan interface{})
go func() {
    b, i := boolInt()
    ch <- b
    ch <- i
}()

fmt.Println("Received values:", <-ch, <-ch)

Output:

Received values: false 1

Answered By – icza

Answer Checked By – Clifford M. (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.