跳出选择循环?

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

Break out of select loop?

问题

我正在尝试在循环中使用select来接收消息或超时信号。如果接收到超时信号,循环应该中止:

package main
import ("fmt"; "time")
func main() {
    done := time.After(1*time.Millisecond)
    numbers := make(chan int)
    go func() {for n:=0;; {numbers <- n; n++}}()
    for {
        select {
            case <-done:
                break
            case num := <- numbers:
                fmt.Println(num)
        }
    }
}

然而,它似乎没有停止:

$ go run a.go
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[...]
3824
3825
[...]

为什么?我使用time.After的方式有问题吗?

英文:

I'm trying to use a select in a loop to receive either a message or a timeout signal. If the timeout signal is received, the loop should abort:

package main
import (&quot;fmt&quot;; &quot;time&quot;)
func main() {
    done := time.After(1*time.Millisecond)
    numbers := make(chan int)
    go func() {for n:=0;; {numbers &lt;- n; n++}}()
    for {
        select {
            case &lt;-done:
                break
            case num := &lt;- numbers:
                fmt.Println(num)
        }
    }
}

However, it doesn't seem to be stopping:

$ go run a.go
0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
[...]
3824
3825
[...]

Why? Am I using time.After wrong?

答案1

得分: 41

根据Go的规范,"break"语句会终止同一函数内最内层的"for"、"switch"或"select"语句的执行。

在你的示例中,你只是跳出了select语句。如果你将"break"替换为"return"语句,你会发现它可以正常工作。

英文:

The Go spec says:

> A "break" statement terminates execution of the innermost "for",
> "switch", or "select" statement within the same function.

In your example you're just breaking out of the select statement. If you replace break with a return statement you will see that it's working.

答案2

得分: 28

在这种情况下,"Go"的做法是使用标签和在标签上使用break,例如:

L:
    for {
        select {
            case <-done:
                break L
            case num := <-numbers:
                fmt.Println(num)
        }
    }

参考:

英文:

The "Go" way for that kind of situations is to use labels and break on the label, for example:

L:
    for {
        select {
            case &lt;-done:
                break L
            case num := &lt;- numbers:
                fmt.Println(num)
        }
    }

Ref:

答案3

得分: 13

在你的示例代码中,正如Pat所说,使用return是合适的,但是以后你可以使用标签(label):

package main

import (
	"fmt"
	"time"
)

func main() {
	done := time.After(1 * time.Millisecond)
	numbers := make(chan int)

	// 发送到通道
	go func() {
		for n := 0; ; {
			numbers <- n
			n++
		}
	}()

readChannel:
	for {
		select {
		case <-done:
			break readChannel
		case num := <-numbers:
			fmt.Println(num)
		}
	}

	// 其他逻辑...
	fmt.Println("Howdy")
}
英文:

In your example code, a return seems appropriate as Pat says, but for future reference you can use labels:

package main

import (
	&quot;fmt&quot;
	&quot;time&quot;
)

func main() {
	done := time.After(1 * time.Millisecond)
	numbers := make(chan int)

	// Send to channel
	go func() {
		for n := 0; ; {
			numbers &lt;- n
			n++
		}
	}()

readChannel:
	for {
		select {
		case &lt;-done:
			break readChannel
		case num := &lt;-numbers:
			fmt.Println(num)
		}
	}

	// Additional logic...
	fmt.Println(&quot;Howdy&quot;)
}

答案4

得分: 9

我有以下解决方案,使用匿名函数。

func() {
    for {
        select {
        case <-time.After(5 * time.Second):
            if token := c.Connect(); token.Wait() && token.Error() != nil {
                fmt.Println("连接错误:", token.Error())
            } else {
                fmt.Println("中断")
                return
            }
        }
    }
}()

请注意,这是一个使用匿名函数的示例代码。

英文:

I have the following solution, by using a anonymous function.

	func() {
	for {
		select {
		case &lt;-time.After(5 * time.Second):
			if token := c.Connect(); token.Wait() &amp;&amp; token.Error() != nil {
				fmt.Println(&quot;connect err:&quot;, token.Error())
			} else {
				fmt.Println(&quot;breaking&quot;)
				return
			}
		}
	}
    }()

答案5

得分: 5

使用一些控制变量来跳过循环怎么样?有时候使用break标签来理解可能有点困难或者不太容易理解。

package main
import ("fmt"; "time")
func main() {
    done := time.After(1*time.Millisecond)
    numbers := make(chan int)
    go func() {for n:=0;; {numbers <- n; n++}}()
    completed := false
    for !completed {
        select {
            case <-done:
                completed = true
                // 这里不需要使用break
            case num := <- numbers:
                fmt.Println(num)
        }
    }
}
英文:

How about using some control variable to skip the loop? It's kind of hard or not so easy to understand with breaking label sometimes.

package main
import (&quot;fmt&quot;; &quot;time&quot;)
func main() {
    done := time.After(1*time.Millisecond)
    numbers := make(chan int)
    go func() {for n:=0;; {numbers &lt;- n; n++}}()
    completed := false
    for !completed {
        select {
            case &lt;-done:
                completed = true
                // no break needed here
            case num := &lt;- numbers:
                fmt.Println(num)
        }
    }
}

huangapple
  • 本文由 发表于 2014年8月24日 15:55:14
  • 转载请务必保留本文链接:https://go.coder-hub.com/25469682.html
匿名

发表评论

匿名网友

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

确定