sumopal
sumopal

Reputation: 337

Difference between passing a channel to a closure as a formal argument vs using the channel defined in the parent scope?

Take these two snippets for example

func Worker() {
    out := make(chan int)

    func() {
        // write something to the channel
    }()
    return out
}
func Worker() {
    out := make(chan int)

    func(out chan int) {
        // write something to the channel
    }(out)
    return out
}

I know that passing arguments to a closure creates a copy of that and using something from the parent scope uses the reference, so I want to know how does this work internally in case of pass by copy. are there two channels one in parent scope and the other copy passed to closure and when the copy in the closure is written to a copy of that value is also made in the channel in the parent scope? because we are returning the out chan in the parent scope to the caller and the values will be consumed from that channel only.

Upvotes: 1

Views: 517

Answers (1)

Maxim Kosov
Maxim Kosov

Reputation: 1980

chan is a reference type just like a slice or a map. Everything in go is passed by value. When you pass chan as an argument it creates a copy of the reference referencing the same value. The channel will be consumable from the parent scope in both cases. But there are couple of differences. Consider the following code:

ch := make(chan int)

var wg sync.WaitGroup
wg.Add(1)
go func() {
    ch <- 1
    ch = nil
    wg.Done()
}()

<-ch // we can read from the channel
wg.Wait()
// ch is nil here because we override the reference with a null pointer

vs

ch := make(chan int)

var wg sync.WaitGroup
wg.Add(1)
go func(ch chan int) {
    ch <- 1
    ch = nil
    wg.Done()
}(ch)

<-ch // we still can read from the channel
wg.Wait()
// ch is not nil here because we override the copied reference not the original one
// the original reference remained the same

Upvotes: 2

Related Questions