Golang的reflect.SelectSend方法不起作用,返回false。

huangapple go评论81阅读模式
英文:

Golang reflect.SelectSend does not work and get false

问题

我正在尝试使用reflect.Select在通道中发送数据。代码如下所示。

c := make(chan int, 1)
vc := reflect.ValueOf(c)
go func() {
	<-c
}()
vSend := reflect.ValueOf(789)
branches := []reflect.SelectCase{
	{Dir: reflect.SelectSend, Chan: vc, Send: vSend},
}
selIndex, _, sentBeforeClosed := reflect.Select(branches)
fmt.Println(selIndex)
fmt.Println(sentBeforeClosed)

但是我发现它不起作用,结果是

0
false

为什么会返回false?我如何监视能够接收数据的通道列表?

英文:

I'm trying to use reflect.Select to send data in a channel. The code is as following.

c := make(chan int, 1)
vc := reflect.ValueOf(c)
go func() {
	&lt;-c
}()
vSend := reflect.ValueOf(789)
branches := []reflect.SelectCase{
	{Dir: reflect.SelectSend, Chan: vc, Send: vSend},
}
selIndex, _, sentBeforeClosed := reflect.Select(branches)
fmt.Println(selIndex)
fmt.Println(sentBeforeClosed)

But I found it doesn't work, the result is

0 
false

why do I get false? How could I monitor a list of channels which could recv data?

答案1

得分: 1

如果你仔细阅读reflect.Select的文档,你会发现第三个返回值只在case的方向是接收操作时才相关。

Select执行由case列表描述的选择操作。与Go的select语句一样,它会阻塞,直到至少有一个case可以执行,然后进行均匀的伪随机选择,然后执行该case。它返回所选case的索引,如果该case是接收操作,则返回接收到的值以及一个布尔值,指示该值是否对应于通道上的发送(而不是因为通道关闭而接收到的零值)。[...]

换句话说,上述意味着在接收操作上,如果通道接收到了实际值,第三个返回值将为true,如果通道接收到通道项类型的零值,因为通道已关闭,则为false

但是你的代码使用了Dir: reflect.SelectSend。在发送操作中,不需要检查布尔值,因为发送case要么被选择,要么不被选择。如果被选择,第一个返回值selIndex将是所选case的索引,这就是你需要知道的全部信息。在这种情况下,第三个返回值false只是因为它是bool类型的零值。

如果你将代码更改为使用Dir: reflect.SelectRecv,那么布尔值将根据上述引用的文档具有意义:

func main() {
	c := make(chan int, 1)
	vc := reflect.ValueOf(c)
	go func() {
		c <- 789
	}()
	branches := []reflect.SelectCase{
		{Dir: reflect.SelectRecv, Chan: vc},
	}
	selIndex, recVal, recOK := reflect.Select(branches)
	fmt.Println(selIndex, recVal, recOK)

	selIndex, recVal, recOK = reflect.Select(branches)
	fmt.Println(selIndex, recVal, recOK)
}

输出:

0 789 true
0 0 false

Playground: https://go.dev/play/p/ezuc_OaK_SW

英文:

If you carefully read reflect.Select documentation, you'll see that the third return value is relevant only when the direction of the case is a receive operation.

> Select executes a select operation described by the list of cases. Like the Go select statement, it blocks until at least one of the cases can proceed, makes a uniform pseudo-random choice, and then executes that case. It returns the index of the chosen case and, if that case was a receive operation, the value received and a boolean indicating whether the value corresponds to a send on the channel (as opposed to a zero value received because the channel is closed). [...]

In other words, the above means that on receive operations the third return value will be true if the channel received an actual value, or false if it received the zero value for the channel item type due to the channel being closed.

But your code uses Dir: reflect.SelectSend. On send operations, it is not necessary to inspect the boolean value because the send case will either be selected or not. If it is, the first return value selIndex will be the index of the selected case, and that's all you need to know. The third return value in this case is false simply because it is the zero value of the bool type.

If you change your code to use Dir: reflect.SelectRecv, then the boolean value will have meaning, based on the above quoted documentation:

func main() {
	c := make(chan int, 1)
	vc := reflect.ValueOf(c)
	go func() {
		c &lt;- 789
	}()
	branches := []reflect.SelectCase{
		{Dir: reflect.SelectRecv, Chan: vc},
	}
	selIndex, recVal, recOK := reflect.Select(branches)
	fmt.Println(selIndex, recVal, recOK)

	selIndex, recVal, recOK = reflect.Select(branches)
	fmt.Println(selIndex, recVal, recOK)
}

Prints:

0 789 true
0 0 false

Playground: https://go.dev/play/p/ezuc_OaK_SW

huangapple
  • 本文由 发表于 2022年5月30日 17:34:46
  • 转载请务必保留本文链接:https://go.coder-hub.com/72432129.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定