2016-04-24 27 views
2

我想通過通道組織兩個功能之間的通信。被叫方只能將數據發送到頻道,而主叫方將在select中等待。我想在被調用者簽名中顯示這個限制。我想要的另一件事是使用通道的類型別名。例如,我不想讓chan stringMsgChan一起定義爲type MsgChan chan string。我面臨的問題 - 如果取消註釋行test1(make(Ch))下面的代碼將無法編譯:在Go中輸入通道的別名奇怪

package main 

import "fmt" 

type Ch chan int 
type ChIn chan<- int 

func test1(in ChIn) { 
    fmt.Println(in) 
} 

func test2(in chan<- int) { 
    fmt.Println(in) 
} 

func main() { 
    //test1(make(Ch)) 
    test1(make(chan int)) 
    test2(make(Ch)) 
    test2(make(ChIn)) 
} 

我不明白爲什麼我不能用這樣的方法?

回答

3

test1()有一個ChIn類型的參數。這是一個命名的類型。您想傳遞一個類型爲Ch的值,這是一個雙向通道類型,也是一個命名類型。

所以爲了編譯,Ch的值應該可以指定爲ChIn。這是語言規範所不允許的。

引用Assignability(強調指出,適用於這裏的一個):

x是分配給T類型( 「x是分配給T」),在任何的這些情況下,variable

  • x的類型與T完全相同。
  • x的類型VT具有相同underlying typesVT至少一個不是命名類型。
  • T是一種接口類型和ximplementsT
  • x是雙向信道值,T是一個信道類型,x的類型VT具有相同的元素類型,和V至少一個或T不是命名類型。
  • x是預定義的標識符nilT是指針,函數,片,映射,通道或接口類型。
  • x是可以用T類型的值表示的無類型constant

你可以,如果你嘗試通過無名類型的值,但具有相同的基本類型,這可以通過使用類型轉換來實現,例如,它的工作:

test1((chan int)(make(Ch))) 

但上述轉換將會破壞名爲Ch類型的目的(因爲您必須重複其類型字面值才能將其轉換爲未命名類型,以便您可以將其傳遞到test1())。

你應該做的是不要隱藏該類型是一個通道(不包括chan在類型聲明的類型字面量中),只爲該通道的元素類型創建一個新類型,例如:

type Msg int 

func test(in chan<- Msg) { 
    fmt.Println(in) 
} 

func main() { 
    test(make(chan Msg)) 
    test(make(chan<- Msg)) 

    ch := make(chan Msg) 
    chIn := (chan<- Msg)(ch) 
    test(chIn) 
} 

試一下Go Playground

+0

太棒了!該規範看起來像是我的情況!不過,我最終爲通道的val類型使用了命名類型,但不是整個通道。 –

+1

@IvanVelichko你應該怎麼做,正如編輯答案中詳述的那樣。 – icza