I have a code that is similar to this:
type Ch chan string
func getCh() Ch {
ch := make(Ch)
go func() {
defer close(ch)
ch <- "foo"
}()
return ch
}
func main() {
fmt.Println(<-getCh())
}
What I would like to do is to return a read-only version of the Ch channel from the getCh function. I've adding a read-only type that is compatible with the Ch channel, and changing the function signature to use this type like this:
type Ch chan string
type ChRo <-chan string
func getCh() ChRo {
ch := make(Ch)
// ...
return ch
}
but this gives a compile error:
cannot use ch (variable of type Ch) as ChRo value in return statement
However if I drop the ChRo type and use native <-chan string as return type it works:
func getCh() <-chan string {
ch := make(Ch)
// ...
return ch
}
Is there a way to use the ChRo type for the return value? The channel in my real code is not actually of string type - it is quite more complex generic struct.
As I understand it - the ChRo type matches exactly the type <-chan string. There is no covariance confusion going on here.
Why
- The first goal here is to have return a read-only channel type. It should be a separate type for readability. And it should be read-only so the consumer won't use it in a write context.
- The second goal is to have the
getChfunction compatibile with another function that will be internally called by thegetCh:
func getCh() <-chan string {
data, err := fetchFromExternalResource() // returns (ChRo, error)
// handle error
return data
}
Think of it like this: The type cannot (and imho) should not decide on how it is used. Interfaces define behavior, functions implement it.
So, the way to go would be to define one or more interfaces which define the desired behavior.
Having that said, what you want can be achieved. Given the following code:
This won't even compile, since the compiler correctly deduces that in
func (ms *Writer) DoSomething(ch MyChannel), we are trying to write to a receive-only channel:Without the
Writer, it works as expected. Run on playground