Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Go 为什么信道的信道方向变化可以';不能兼容吗?_Go_Channel - Fatal编程技术网

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