动态创建通道以用作Go中可变参数函数的参数

Is it possible to dynamically create a channel in Go and then assign it a value? This fan-out-fan-in code works with

f1 := factorial(in)
f2 := factorial(in)
for n := range merge(f1, f2) { 
        fmt.Println(n)
}

But I'd like to do something like

var res [2]<-chan int
res[0] = make(chan int)
res[0] = factorial(in)
res[1] = make(chan int)
res[1] = factorial(in)
for n := range merge(res...)
    fmt.Println(n)
}

This gives the following error

$ go run main.go
# command-line-arguments
.\main.go:26: cannot use res (type [2]<-chan int) as type []<-chan int in 
argument to merge

Here is the full code...

package main

import (
    "fmt"
    "sync"
)

func main() {

    in := gen()

    f1 := factorial(in) // code to be replaced
    f2 := factorial(in) // code to be replaced
    for n := range merge(f1, f2) { // code to be replaced
        fmt.Println(n) // code to be replaced
    } // code to be replaced

    // What I'd like to use instead of the above...
    //var res [2]<-chan int
    //res[0] = make(chan int)
    //res[0] = factorial(in)
    //res[1] = make(chan int)
    //res[1] = factorial(in)
    // for n := range merge(res...)
    //  fmt.Println(n)
    //}
    // This commented code generates the following error
    //$ go run main.go
    //# command-line-arguments
    //.\main.go:20: cannot use res (type [2]<-chan int) as type []<-chan int in argument to merge

}

func gen() <-chan int {
    out := make(chan int)
    go func() {
        for i := 0; i < 100; i++ {
            for j := 3; j < 13; j++ {
                out <- j
            }
        }
        close(out)
    }()
    return out
}

func factorial(in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        for n := range in {
            out <- fact(n)
        }
        close(out)
    }()
    return out
}

func fact(n int) int {
    total := 1
    for i := n; i > 0; i-- {
        total *= i
    }
    return total
}

func merge(cs ...<-chan int) <-chan int {
    out := make(chan int)
    var wg sync.WaitGroup
    wg.Add(len(cs))
    for _, c := range cs {
        go func(ch <-chan int) {
            for n := range ch {
                out <- n
            }
            wg.Done()
        }(c)
    }
    go func() {
        wg.Wait()
        close(out)
    }()
    return out
}

You have two problems:

  1. A variadic function takes multiple args (fmt.Println, for example, takes multiple interface{}). You're sending an array.

  2. An array which is size [2] is not the same as size [] (yes, size of array is part of the type in go).

What you want is something like:

    for n := range merge(res[:]) {

...

func merge(cs []<-chan int) <-chan int {
out := make(chan int)
var wg sync.WaitGroup
wg.Add(len(cs))
for _, c := range cs {
    go func(ch <-chan int) {
        for n := range ch {
            out <- n
        }
        wg.Done()
    }(c)
}
go func() {
    wg.Wait()
    close(out)
}()
return out

}

https://play.golang.org/p/zTrrsRkKJV

Selecting chan per goroutine take resources. When you have N'th channel, goroutine should be N'th. You should use reflect.Select

package main

import (
    "fmt"
    "math/rand"
    "reflect"
    "sync"
    "time"
)

func multpleSelect(chans []chan bool) (int, bool, bool) {
    cases := make([]reflect.SelectCase, len(chans))
    for i, ch := range chans {
        cases[i] = reflect.SelectCase{
            Dir: reflect.SelectRecv,
            Chan: reflect.ValueOf(ch),
        }
    }

    i, v, ok := reflect.Select(cases)
    return i, v.Interface().(bool), ok
}

func main() {
    rand.Seed(time.Now().UnixNano())

    chans := make([]chan bool, 100)
    for i := 0; i < 100; i++ {
        chans[i] = make(chan bool)
    }


    var wg sync.WaitGroup
    go func() {
        wg.Add(1)

        if ch, v, ok := multpleSelect(chans); ok {
            fmt.Printf("I am chan-%v, value is %v
", ch, v)
        }
        wg.Done()
    }()

    chans[rand.Int() % len(chans)] <- true

    wg.Wait()
}