英文:
cannot use make(IntChannel) (value of type IntChannel) as Consumer value in variable declaration
问题
我们有以下场景:
package main
type Consumer chan interface {
OpenChannel()
CloseChannel()
}
type IntChannel chan int
type StringChannel chan string
func (c IntChannel) OpenChannel() {
}
func (c IntChannel) CloseChannel() {
}
func (c StringChannel) OpenChannel() {
}
func (c StringChannel) CloseChannel() {
}
func main() {
var dataChannel Consumer = make(IntChannel)
for data = range dataChannel {
}
}
目标是在 dataChannel
上使用 range
。
var dataChannel Consumer = make(IntChannel)
出现错误:cannot use make(IntChannel) (value of type IntChannel) as Consumer value in variable declaration
。
根据运行时给定的配置值,我们选择 int 类型的通道或 string 类型的通道。
阅读这个答案,但没有太多帮助。
如何在选择 int 数据或 string 数据的通道类型上使用 range
?
英文:
We have a below scenario:
package main
type Consumer chan interface {
OpenChannel()
CloseChannel()
}
type IntChannel chan int
type StringChannel chan string
func (c IntChannel) OpenChannel() {
}
func (c IntChannel) CloseChannel() {
}
func (c StringChannel) OpenChannel() {
}
func (c StringChannel) CloseChannel() {
}
func main() {
var dataChannel Consumer = make(IntChannel)
for data = range dataChannel {
}
}
Goal is to range
on dataChannel
.
var dataChannel Consumer = make(IntChannel)
gives error: cannot use make(IntChannel) (value of type IntChannel) as Consumer value in variable declaration
We pick int channel or string channel based on a given config value at runtime.
Read this answer, but not much help.
How to range on a channel type that picks either int data or string data?
答案1
得分: 3
首先,你将Consumer
声明为chan
类型的interface{ /* methods */ }
,这几乎肯定不是你想要的——实际上,错误提示说明你不能将IntChannel
赋值给它。
然后,在语言中添加泛型之前,你没有办法保持类型安全。
最接近你想要做的解决方案可能是在接口中添加一个额外的方法,该方法返回可以进行range
迭代的内容。
type Consumer interface {
OpenChannel()
CloseChannel()
Range() <-chan interface{}
}
type IntChannel chan int
func (c IntChannel) OpenChannel() {
}
func (c IntChannel) CloseChannel() {
}
func (c IntChannel) Range() <-chan interface{} {
ret := make(chan interface{})
go func() {
defer close(ret)
for v := range c {
ret <- v
}
}()
return ret
}
func main() {
c := make(IntChannel)
var dataChannel Consumer = c
go func() {
c <- 12
close(c)
}()
for data := range dataChannel.Range() {
fmt.Println(data)
}
}
Go1 Playground: https://play.golang.org/p/55BpISRVadE
使用泛型(Go 1.18,2022年初),相反,你可以定义一个具有底层类型chan
的参数化类型:
package main
import "fmt"
type GenericChan[T] chan T
func main() {
c := make(GenericChan[int])
go func() {
c <- 12
close(c)
}()
for data := range c {
fmt.Println(data)
}
}
Go2 Playground: https://go2goplay.golang.org/p/HQJ36ego97i
英文:
First, you declared Consumer
as a chan
of interface{ /* methods */ }
, which most surely isn't what you want — as a matter of fact, the error tells that you can't assign IntChannel
to it.
Then, until generics are added to the language, you don't have a way to preserve type safety.
The closest solution to what you want to do might be adding an additional method to the interface that returns something that you can range
over.
type Consumer interface {
OpenChannel()
CloseChannel()
Range() <-chan interface{}
}
type IntChannel chan int
func (c IntChannel) OpenChannel() {
}
func (c IntChannel) CloseChannel() {
}
func (c IntChannel) Range() <-chan interface{} {
ret := make(chan interface{})
go func() {
defer close(ret)
for v := range c {
ret <- v
}
}()
return ret
}
func main() {
c := make(IntChannel)
var dataChannel Consumer = c
go func() {
c <- 12
close(c)
}()
for data := range dataChannel.Range() {
fmt.Println(data)
}
}
Go1 Playground: https://play.golang.org/p/55BpISRVadE
<hr>
With generics (Go 1.18, early 2022), instead you can just define a parametrized type with underlying type chan
:
package main
import "fmt"
type GenericChan[T] chan T
func main() {
c := make(GenericChan[int])
go func() {
c <- 12
close(c)
}()
for data := range c {
fmt.Println(data)
}
}
Go2 Playground: https://go2goplay.golang.org/p/HQJ36ego97i
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论