我有一个与此类似的代码:
type Ch chan string
func getCh() Ch {
ch := make(Ch)
go func() {
defer close(ch)
ch <- "foo"
}()
return ch
}
func main() {
fmt.Println(<-getCh())
}
我想做的是从
Ch
函数返回 getCh
通道的只读版本。我添加了一个与 Ch
通道兼容的只读类型,并更改函数签名以使用此类型,如下所示:
type Ch chan string
type ChRo <-chan string
func getCh() ChRo {
ch := make(Ch)
// ...
return ch
}
但这会产生编译错误:
cannot use ch (variable of type Ch) as ChRo value in return statement
但是,如果我删除
ChRo
类型并使用本机 <-chan string
作为返回类型,则它可以工作:
func getCh() <-chan string {
ch := make(Ch)
// ...
return ch
}
有没有办法使用
ChRo
类型作为返回值?我的真实代码中的通道实际上并不是 string
类型 - 它是相当复杂的通用结构。
据我了解 -
ChRo
类型与 <-chan string
类型完全匹配。这里没有发生协方差混乱。
getCh
函数与 getCh
内部调用的另一个函数兼容:func getCh() <-chan string {
data, err := fetchFromExternalResource() // returns (ChRo, error)
// handle error
return data
}
这样想:类型不能(恕我直言)不应该决定它的使用方式。接口定义行为,函数实现它。
因此,解决方法是定义一个或多个定义所需行为的接口。
话虽如此,你想要的都能实现。 给出以下代码:
package main
import "fmt"
type MyChannel <-chan string
type Stuff interface {
// DoSomething implicitly requires a read-only channel.
DoSomething(MyChannel)
}
type Reader struct {
Prefix string
}
func (ms *Reader) DoSomething(ch MyChannel) {
fmt.Printf("%s, %s!\n", ms.Prefix, <-ch)
}
type Writer struct {
Prefix string
}
func (ms *Writer) DoSomething(ch MyChannel) {
ch <- fmt.Sprintf("%s, %s", ms.Prefix, "world")
}
func callStuff(stuff Stuff, ch MyChannel) {
stuff.DoSomething(ch)
}
func main() {
s := Reader{"Hello"}
ch := make(chan string)
go func() {
ch <- "world"
}()
callStuff(&s, ch)
w := Writer{"Goodbye"}
callStuff(&w, ch)
fmt.Printf("Received: %s\n", <-ch)
}
这甚至无法编译,因为编译器在
func (ms *Writer) DoSomething(ch MyChannel)
中正确推断出我们正在尝试写入仅接收通道:
./main.go:25:2: invalid operation: cannot send to receive-only channel ch (variable of type MyChannel)