我正在阅读一些go代码,并说了几种传递go通道的方法。 也许它们是相同的,但是我想知道是否存在任何差异,因为我无法在线找到文档:

1)

1
func serve(ch <-chan interface{}){ //do stuff }

2)

1
func serve(ch chan<- interface{}){ //do stuff }

3)

1
func serve(ch chan interface{}){ //do stuff }

4)

1
func server(ch *chan interface{}){ //do stuff}

我想知道它们之间有什么区别,以及它们是否只是做同一件事的等效方法:在不同的goroutine周围传递通道。

注意:我知道没有理由将指针传递到chan,map或slice或函数值,因为这些都是内部包含指针的引用类型(例外是如果您希望被调用者更改 引用类型标题)。 我提供它的唯一原因是出于完整性考虑(即真正提供尝试将通道作为参数传递的所有方法,并提出希望可以参考所有方法进行比较的问题)。


我总是建议您尽可能将方向传递给其他人,例如

1
2
3
func serve(ch <-chan SomeType) { /*do stuff*/ }

func serve(ch chan<- SomeType) { /*do stuff*/ }

通过包含箭头<-chanchan<-,您可以实现三件事:

  • 您很清楚该参数是通道的结尾。
  • 您正在明确表达要提供的是哪一端。
  • 您正在向编译器提供更多信息以进行检查。如果函数主体尝试使用错误的通道结尾,则编译器可能会引发错误。

这些是在可能的情况下显示通道结束的充分理由。

您的第三种情况是未指定频道的结尾。这样可以访问通道的两端,在某些情况下这是正确的,但在其他情况下可能会导致意外错误。

第四种情况是将指针传递给通道,这很不寻常,也许有些奇怪。如果您想更改通道,则将其包含为返回参数会更加清楚。

  • 好的答案,只是"结束"的正确术语是"方向" /"通道方向"。请在规格中查看。
  • 规范确实说明了方向,但这不一定对新手有所帮助。使用CSP设计时,您可以松散地考虑管道(例如流体管道)的情况-将其一端倒入另一端。在Occam中,这种区别是明确的,但是在Go中,(故意)它更加模糊。特别是,使用Go可以在单个goroutine中完全使用缓冲通道,因此规范指的是方向而不是终点。这种用法在CSP中是不可能的,但是Gos渠道的实现是灵活的并且允许这样做。
  • 另外,在考虑网络是否可能出现死锁时考虑通道结束可能会有所帮助。有理论证明,有向图如果是非循环的,则无死锁。您需要考虑渠道的方向以对此进行推理。端点和方向实际上是可以互换的-两者都是有用的概念。

这些是不同类型的渠道。请参阅http://golang.org/ref/spec#Channel_types。对于指针来说:不常见,但是如果您想从函数内部更改通道(从来没有在野外看到过)可能会很有用。


经验法则:箭头显示数据是进入(输出)通道还是离开(输入)通道。通用渠道是没有箭头。

1
2
3
chan <-          writing to channel (output channel)
<- chan          reading from channel (input channel)
chan             read from or write to channel (input/output channel)