I want to organize communication between two functions via channels. The callee can only send data to the channel while the caller will wait for it in the select
. And I want to show this restriction in the callee signature. Another thing that I want is working with type aliases for channels. For example, instead of having chan string
I want to work with MsgChan
defined as type MsgChan chan string
. And I faced with the problem - the code below won't compile if uncomment line test1(make(Ch))
:
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))
}
I don't understand why I can't use such approach?
test1()
has one parameter of type ChIn
. This is a named type. You want to pass a value of type Ch
which is a bidirectional channel type, and is also a named type.
So in order for this to compile, a value of Ch
should be assignable to type ChIn
. This is not allowed by the language specification.
Quoting Assignability (highlighted the one that applies here):
A value
x
is assignable to a variable of typeT
("x
is assignable toT
") in any of these cases:
x
's type is identical toT
.x
's typeV
andT
have identical underlying types and at least one ofV
orT
is not a named type.T
is an interface type andx
implementsT
.x
is a bidirectional channel value,T
is a channel type,x
's typeV
andT
have identical element types, and at least one ofV
orT
is not a named type.x
is the predeclared identifiernil
andT
is a pointer, function, slice, map, channel, or interface type.x
is an untyped constant representable by a value of typeT
.
You can make it work if you try to pass a value of unnamed type but having the same underlying type, which can be achieved by using a type conversion, e.g.:
test1((chan int)(make(Ch)))
But the above conversion would defeat the purpose of having the named Ch
type (as you have to repeat its type literal in order to convert it to an unnamed type just so you can pass it to test1()
).
What you should do is don't hide that the type is a channel (don't include chan
in the type literal of the type declaration), only create a new type for the element type of the channel, e.g.:
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)
}
Try it on the Go Playground.