结构中的 Golang 通道:传递给函数时可以是定向的吗?

Posted

技术标签:

【中文标题】结构中的 Golang 通道:传递给函数时可以是定向的吗?【英文标题】:Golang channel in a struct: Can it be directional when passed to a function? 【发布时间】:2017-11-03 22:29:12 【问题描述】:

当将通道传递给函数时,我知道您可以指定通道可能使用通道的方向;例如,

func MyFunc(ch chan<- string) 
    ch <- "Hello"

“ch”只能被 MyFunc 用来向其他地方的接收者发送字符串,而 MyFunc 不能监听来自 ch 的消息。

为了简化为一些 goroutine 创建动态数量的通道,我创建了一个包含通道的结构。

type ChanStruct struct 
    chMessages chan string

然后我实例化一个结构体:

var slcChanStruct []ChanStruct
for a:= 0; a <=2; a++ 
    var tmpChanStruct ChanStruct
    tmpChanStruct.chMessages = make(chan string)
    slcChanStruct = append(slcChanStruct, tmpChanStruct)

现在我有 3 个结构,我可以通过遍历一个结构片来单独读取/写入通道。但是当我将它们发送到 goroutines 时:

for a:=0; a <=2; a++
    go SomeFunc(slcChanStruct[a])

...有没有办法通过指定 goroutines 只能使用 ChanStruct.ch 通道发送来增加一点安全性?

注意我这样做的原因是,如果我不知道使用带有通道的结构体的一组并行进程(进程数作为命令行参数传递)需要多少个通道,则意味着我可以创建一个可以传递给任意数量的 goroutine 的切片,并通过遍历它们来单独访问它们;以前,如果我想从多个 goroutine 中单独读取,我必须创建一组通道。我想通过指定进程只能以某种方式使用通道来增加一些安全性,就像我在使用单个通道时一样(单个通道意味着我可以做一些事情,比如告诉一个特定的 goroutine 在没有其他 goroutine 拦截的情况下退出它)。如果我无法使用结构中的通道向函数添加方向性,是否有更惯用的方法来做到这一点?

【问题讨论】:

【参考方案1】:

有几种方法,具体取决于您的具体情况:

传递通道而不是结构,并使通道参数与第一个示例一样具有方向性 不要直接暴露通道,只暴露一个结构体方法来写入(如果没有方法可以从中读取,它实际上是定向的) 使通道结构成员定向:

例如

type myStruct struct 
    c chan <- bool

【讨论】:

感谢您的回复!我曾考虑过第三个示例,但如果我使结构成员具有方向性,我将如何在接收方读取它?那岂不是不可能了? 接收者必须保留它自己的通道副本,该副本要么不是定向的,要么是只接收的,就像您在原始示例中将定向通道直接传递给函数一样.【参考方案2】:

根据@Adrian 的建议,如果您必须确保在频道上进行单向通信,您可以随时使用匿名函数:

for a:=0; a <=2; a++
  go func f(ch <-string) 
    SomeFunc(ch)
  (slcChanStruct[a].chMessages)

请注意,您必须将通道传递给 SomeFunc 而不是结构。

如果您仍想在频道上执行双向通信,您可以将频道重新分配为单向类型:

type ChanStruct struct 
    chMessages chan string


type ChanStructRecv struct 
    chMessages <-chan string


// Update SomeFunc type:

func SomeFunc(s ChanStructRecv) 
  // ...

最后可以类似地修改循环:

for a:=0; a <=2; a++
  go func f(s ChanStruct) 
    var sr ChanStructRecv
    sr.chMessages = s.chMessages
    SomeFunc(sr)
  (slcChanStruct[a])

【讨论】:

以上是关于结构中的 Golang 通道:传递给函数时可以是定向的吗?的主要内容,如果未能解决你的问题,请参考以下文章

选择中的Golang频道未接收

Golang语言社区投稿golang高并发基于协程,通道的任务池

C:为啥你可以通过值传递(给函数)一个结构,而不是一个数组?

Golang中的init函数

Golang入门到项目实战 | golang函数的参数

Golang使用小写字母作为Struct属性中的第一个字母