Go 为什么信道的信道方向变化可以';不能兼容吗?
我喜欢编程,尽可能严格地提供接口,既要避免不好的使用,又要明确和自我记录 所以,我喜欢在用户单向使用时提供定向通道,但当然,在内部我有一个双向通道副本 以下工程的协助:Go 为什么信道的信道方向变化可以';不能兼容吗?,go,channel,Go,Channel,我喜欢编程,尽可能严格地提供接口,既要避免不好的使用,又要明确和自我记录 所以,我喜欢在用户单向使用时提供定向通道,但当然,在内部我有一个双向通道副本 以下工程的协助: var internal chan int var external <-chan int external = internal var内部通道int var external这种情况在某种程度上类似于使用用户级泛型的语言中遇到的问题。在使用其内部泛型类型等价物(称为“复合类型”)时,您也可以在Go中遇到它。例如: t
var internal chan int
var external <-chan int
external = internal
var内部通道int
var external这种情况在某种程度上类似于使用用户级泛型的语言中遇到的问题。在使用其内部泛型类型等价物(称为“复合类型”)时,您也可以在Go中遇到它。例如:
type A struct{}
// All `B`s are convertible to `A`s
type B A
甚至:
type A interface{}
// B embeds A
type B interface{ A }
var b B
// This works without problem
var a A = A(b)
但请考虑以下情况:
var bs []B
var as []A = ([]A)(bs)
此处,编译失败,错误为无法将bs(类型[]B)用作赋值中的类型[]A
。尽管任何B
都可以转换为等价的A
,但对于[]B
和[]A
(或chan B
和chan A
,或map[string]B
和map[string]A
,或func(A)
和func(B)而言,情况并非如此
或在其定义中使用A
s和B
s的任何其他通用类型)。尽管类型可以相互转换,但它们并不相同,而且这些泛型在Go中的工作方式是,从规范:
每个类型T都有一个底层类型:如果T是预声明类型或类型文本,则对应的底层类型是T本身。否则,T的基础类型是T在其类型声明中引用的类型的基础类型
字符串T1和T2的基本类型是string。[]T1、T3和T4的基本类型是[]T1
请注意,[]T1
的底层类型是[]T1
,而不是[]string
。这意味着[]T2
的基础类型将是[]T2
,而不是[]string
或[]T1
,这使得它们之间无法进行转换
基本上,您正在尝试执行以下操作:
var internal chan Type1
var external <-chan Type2
external = internal
同样的事情
基本上与您的第一个示例相同,只是您必须在“读/写”和“只读(或写)别名”中更深一层。我怀疑这是可能的,因为您必须同时转换外部通道和内部通道的类型。一次一个有效
我喜欢将这些仅发送/接收通道看作是限制函数中可以执行的操作的一种很好的方式:您有一个var c chan int
,然后将它传递给func f(ro),这就是为什么不起作用的原因
该规范说明了以下内容:
[channel]值x
可分配给T
类型的变量(“x可分配给T”)[when]x
是双向通道值,T
是通道类型,x
的类型V
和T
具有相同的元素类型,并且V
或T
中至少有一个不是命名类型
这正好反映了您的体验:
chan(chan int)
至您可能想解释更多关于协方差与逆变的内容,我不确定这是否有助于操作。我认为您在回答中很好地解释了它的要点。但为了更清楚,我完成了我的部分。感谢您的反馈!这不是“几乎就像转换”,是这样的。元素类型是不同的,所以你要对元素类型进行类型转换。
type T1 string
type T2 T1
type T3 []T1
type T4 T3
var internal chan Type1
var external <-chan Type2
external = internal
package main
import "fmt"
// This has the correct signature you wanted
func ExportedFunction(c <-chan (chan<- int)) {
// Sends 1 to the channel it receives
(<-c)<- 1
}
func main() {
// Note that this is a READ/WRITE channel of WRITE-ONLY channels
// so that the types are correct
internal := make(chan (chan<- int))
var external <-chan (chan<- int)
// This works because the type of elements in the channel is the same
external = internal
// This channel is internal, so it is READ/WRITE
internal2 := make(chan int)
// This is typically called externally
go ExportedFunction(external)
fmt.Println("Sending channel...")
// The type of internal makes the receiving end of internal/external
// see a WRITE-ONLY channel
internal <- internal2
fmt.Println("We received:")
fmt.Println(<-internal2)
}
var internal chan chan<- int
var external <-chan chan<- int
external = internal
var internal chan chan int
var internalCopy chan chan<- int
go func() { for e := range internal { internalCopy <- e } }()
var external <-chan chan<- int
external = internalCopy