3 回答
TA贡献1853条经验 获得超18个赞
这不起作用的原因
规范说明了有关通道可分配性的内容:
[通道] 值x可分配给类型变量T(“x 可分配给 T”)[当]x是双向通道值,T是通道类型,x的类型V并T具有相同的元素类型,并且至少有一个V或T不是命名类型。
这正是您所经历的:
chan (chan int)以<- chan (chan int)作品
chan (chan int)对<- chan (chan<- int)不
原因是元素类型(chan关键字之后的)不相等。
我可以申报但不能使用吗?
您可以使用它,但不能以您想要的方式使用。不可能按照您的方式分配变量,但通过更正元素类型,您确实可以使用它:
var internal chan chan<- int
var external <-chan chan<- int
external = internal
如果你只有你的chan chan int类型,你需要复制你的值(播放示例):
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
TA贡献1876条经验 获得超5个赞
这种情况有点类似于在具有用户级泛型的语言中遇到的协变和逆变问题。在 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)
在这里,编译失败并显示错误cannot use bs (type []B) as type []A in assignment。尽管 anyB可以转换为等效的A,但这不适用于[]Band []A(或chan Band chan A、 or map[string]Band map[string]A、 or func(a A)andfunc(b B)或在其定义中使用As 和Bs 的任何其他泛型类型)。尽管类型可以相互转换,但它们并不相同,这些generics在 Go 中的工作方式来自规范:
每个类型 T 都有一个底层类型:如果 T 是预先声明的类型或类型文字,则对应的底层类型是 T 本身。否则,T 的基础类型是 T 在其类型声明中引用的类型的基础类型。
type T1 string
type T2 T1
type T3 []T1
type T4 T3
字符串、T1 和 T2 的基础类型是字符串。[]T1、T3 和 T4 的基础类型是 []T1。
请注意,这里的基础类型[]T1是[]T1,而不是[]string。这意味着[]T2will的基础类型是[]T2,not []stringor []T1,这使得它们之间的转换变得不可能。
基本上,您正在尝试执行以下操作:
var internal chan Type1
var external <-chan Type2
external = internal
这是失败Type1和Type2两种不同的类型,至于类型系统而言。
协变和逆变是非常困难的问题,因为维基百科文章的长度或在 Java 或 C# 中解开有界泛型层所花费的任何时间都会告诉您。这是泛型如此难以实现并引发如此多争论的原因之一。
您可以通过在只读和读/写通道之间的别名上更深一层来获得所需的行为,就像您在第一个示例中对internal/external通道所做的一样:
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)
}
同样的事情在操场上。
基本上与您的第一个示例相同,除了您必须在“读/写”与“仅读(或写)”别名中更深入一层。
- 3 回答
- 0 关注
- 193 浏览
添加回答
举报