3 回答

TA貢獻1853條經(jīng)驗 獲得超18個贊
這不起作用的原因
規(guī)范說明了有關通道可分配性的內(nèi)容:
[通道] 值x可分配給類型變量T(“x 可分配給 T”)[當]x是雙向通道值,T是通道類型,x的類型V并T具有相同的元素類型,并且至少有一個V或T不是命名類型。
這正是您所經(jīng)歷的:
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條經(jīng)驗 獲得超5個贊
這種情況有點類似于在具有用戶級泛型的語言中遇到的協(xié)變和逆變問題。在 Go 中使用泛型類型的內(nèi)部等價物(它們被稱為“復合類型”)時,您也可以遇到它。例如:
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 中的工作方式來自規(guī)范:
每個類型 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,這使得它們之間的轉換變得不可能。
基本上,您正在嘗試執(zhí)行以下操作:
var internal chan Type1
var external <-chan Type2
external = internal
這是失敗Type1和Type2兩種不同的類型,至于類型系統(tǒng)而言。
協(xié)變和逆變是非常困難的問題,因為維基百科文章的長度或在 Java 或 C# 中解開有界泛型層所花費的任何時間都會告訴您。這是泛型如此難以實現(xiàn)并引發(fā)如此多爭論的原因之一。
您可以通過在只讀和讀/寫通道之間的別名上更深一層來獲得所需的行為,就像您在第一個示例中對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 關注
- 210 瀏覽
添加回答
舉報