如何返回作为另一个通道类型的只读版本的命名通道类型?

问题描述 投票:0回答:1

我有一个与此类似的代码:

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
类型完全匹配。这里没有发生协方差混乱

为什么

  1. 这里的第一个目标是返回只读通道类型。为了可读性,它应该是一个单独的类型。并且它应该是只读的,这样消费者就不会在写入上下文中使用它。
  2. 第二个目标是让
    getCh
    函数与
    getCh
    内部调用的另一个函数兼容:
func getCh() <-chan string {
    data, err := fetchFromExternalResource() // returns (ChRo, error)
    // handle error
    return data
}
go concurrency channel
1个回答
0
投票

这样想:类型不能(恕我直言)不应该决定它的使用方式。接口定义行为,函数实现它。

因此,解决方法是定义一个或多个定义所需行为的接口。

话虽如此,你想要的都能实现。 给出以下代码:

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)
© www.soinside.com 2019 - 2024. All rights reserved.