如何将通道切片作为可变参数传递给函数?

huangapple go评论93阅读模式
英文:

How can I pass a channel slice to a function as variadic?

问题

如果我有一个函数,它接受一些只读通道的数量(例如用于通道聚合),为什么我不能用通道切片来调用这个函数呢?

package main

func f(in ...<-chan int) {
    // do something
}

func main() {
    chList := []chan int{make(chan int), make(chan int)}
    f(make(chan int), make(chan int)) // 可行
    f(chList...) // 无法将 chList(类型为 []chan int)作为参数传递给 f 中的类型 []<-chan int
}

我似乎缺少一些基本的东西,但我无法弄清楚是什么。如果函数不能接受单向通道,为什么在第一个例子中可以接受它们呢?

英文:

If I have a function that takes a number of read only channels (for example for channel aggregation), why can't I call this function with a slice of channels, like

package main
func f(in ...&lt;-chan int) {
    // do something
}

func main() {
    chList := []chan int{make(chan int), make(chan int)}
	f(make(chan int), make(chan int)) // works
    f(chList...) // cannot use chList (type []chan int) as type []&lt;-chan int in argument to f
}

It seems I'm missing something fundamental but I can't figure out what. If the function can't take unidirectional channels, why can it take them when not in the first case?

答案1

得分: 1

好的,下面是翻译好的代码部分:

package main

import (
	"fmt"
	"time"
)

func f(in ...<-chan int) chan int {
	fmt.Println("通道数量:", len(in))
	out := make(chan int)
	for _, ch := range in {
		go func(ch <-chan int) {
			for i := range ch {
				out <- i
			}
		}(ch)
	}
	return out
}

func chConv(channels ...chan int) []<-chan int {
	ret := make([]<-chan int, len(channels))
	for n, ch := range channels {
		ret[n] = ch
	}
	return ret
}

func main() {
	chList := []chan int{make(chan int), make(chan int)}
	roChans := chConv(chList...)
	agg := f(roChans...)
	go func() {
		for i := range agg {
			fmt.Println("收到:", i)
		}
	}()
	for i := 0; i < 10; i++ {
		for _, ch := range chList {
			ch <- i
		}
	}
	time.Sleep(1 * time.Second)
}

这段代码涉及到了Go语言中切片协变性的问题。解决方案是将"nondirectional"通道的切片转换为只读通道的切片。完整的示例代码如上所示。

英文:

Ok, so it seems it has to do with lack of slice covariance in go. My solution is to type convert the slice of "nondirectional" channels into a slice of readonly channels. Full example below:

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func f(in ...&lt;-chan int) chan int {
	fmt.Println(&quot;number of channels:&quot;, len(in))
	out := make(chan int)
	for _, ch := range in {
		go func(ch &lt;-chan int) {
			for i := range ch {
				out &lt;- i
			}
		}(ch)
	}
	return out
}

func chConv(channels ...chan int) []&lt;-chan int {
	ret := make([]&lt;-chan int, len(channels))
	for n, ch := range channels {
		ret[n] = ch
	}
	return ret
}

func main() {
	chList := []chan int{make(chan int), make(chan int)}
	roChans := chConv(chList...)
	agg := f(roChans...)
	go func() {
		for i := range agg {
			fmt.Println(&quot;got:&quot;, i)
		}
	}()
	for i := 0; i &lt; 10; i++ {
		for _, ch := range chList {
			ch &lt;- i
		}
	}
	time.Sleep(1 * time.Second)
}

答案2

得分: 0

你错过了方向,

package main
func f(in ...<-chan int) {
    // 做一些事情
}

func main() {
    chList := []<-chan int{make(<-chan int), make(<-chan int)}
    f(make(<-chan int), make(<-chan int)) 
    f(chList...) 
}
英文:

you missed the direction,

package main
func f(in ...&lt;-chan int) {
    // do something
}

func main() {
    chList := []&lt;-chan int{make(&lt;-chan int), make(&lt;-chan int)}
    f(make(&lt;-chan int), make(&lt;-chan int)) 
    f(chList...) 
}

huangapple
  • 本文由 发表于 2016年11月4日 17:23:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/40419047.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定