在 Go 中为通道输入别名工作很奇怪
Type alias for channel in Go works strange
我想通过通道组织两个函数之间的通信。被调用者只能向通道发送数据,而调用者将在 select
中等待。我想在被调用者签名中显示此限制。我想要的另一件事是使用通道的类型别名。例如,我不想使用 chan string
,而是将 MsgChan
定义为 type MsgChan chan string
。我遇到了这个问题——如果取消注释行 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))
}
我不明白为什么我不能使用这种方法?
test1()
有一个 ChIn
类型的参数。这是一个命名类型。您想要传递类型为 Ch
的值,它是双向通道类型,也是命名类型。
因此,为了使其能够编译,Ch
的值应该可以分配给类型 ChIn
。语言规范不允许这样做。
引用 Assignability(突出显示适用于此处的内容):
A value x
is assignable to a variable of type T
("x
is assignable to T
") in any of these cases:
x
's type is identical to T
.
x
's type V
and T
have identical underlying types and at least one of V
or T
is not a named type.
T
is an interface type and x
implements T
.
x
is a bidirectional channel value, T
is a channel type, x
's type V
and T
have identical element types, and at least one of V
or T
is not a named type.
x
is the predeclared identifier nil
and T
is a pointer, function, slice, map, channel, or interface type.
x
is an untyped constant representable by a value of type T
.
如果您尝试传递未命名类型但具有相同基础类型的值,则可以使其工作,这可以通过使用类型转换来实现,例如:
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 上试试。
我想通过通道组织两个函数之间的通信。被调用者只能向通道发送数据,而调用者将在 select
中等待。我想在被调用者签名中显示此限制。我想要的另一件事是使用通道的类型别名。例如,我不想使用 chan string
,而是将 MsgChan
定义为 type MsgChan chan string
。我遇到了这个问题——如果取消注释行 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))
}
我不明白为什么我不能使用这种方法?
test1()
有一个 ChIn
类型的参数。这是一个命名类型。您想要传递类型为 Ch
的值,它是双向通道类型,也是命名类型。
因此,为了使其能够编译,Ch
的值应该可以分配给类型 ChIn
。语言规范不允许这样做。
引用 Assignability(突出显示适用于此处的内容):
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
.
如果您尝试传递未命名类型但具有相同基础类型的值,则可以使其工作,这可以通过使用类型转换来实现,例如:
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 上试试。