英文:
How to read a key in Go but continue application if no key pressed within x seconds?
问题
这是从控制台读取按键的简单方法:
reader := bufio.NewReader(os.Stdin)
// ...
func readKey() rune {
char, _, err := reader.ReadRune()
if err != nil {
fmt.Println("Error reading key: ", err)
}
return char
}
// ...
fmt.Println("Checking keyboard input...")
loop:
for {
keyb := readKey()
switch keyb {
case 'x':
fmt.Println("x key pressed, exiting loop")
break loop
}
}
然而,问题是应用程序总是等待读取按键。如果你只想等待5秒钟读取按键,如果没有按键被读取,继续执行应用程序怎么办?
我认为我可能需要引入一个依赖项,比如ncurses或者一个名为crt的turbopascal中的单元(模块),其中有一个readkey函数。但是是否真的需要一个依赖项,还是有一种简单的方法可以做到呢?可能甚至可以使用一些defer()的技巧,我不确定。
英文:
This is an easy way to read a key from the console
reader := bufio.NewReader(os.Stdin)
// ...
func readKey() rune {
char, _, err := reader.ReadRune()
if err != nil {
fmt.Println("Error reading key: ", err)
}
return char
}
// ...
fmt.Println("Checking keyboard input...")
loop:
for {
keyb := readKey()
switch keyb {
case 'x':
fmt.Println("x key pressed, exiting loop")
break loop
}
}
However the issue is the application always waits for a key to be read. What if you want to wait only 5 seconds for a key to be read, and if no key is read, continue the application?
I'm thinking that I must pull in a dependency maybe, such as ncurses or a unit (module) that turbopascal had which was called crt and had a readkey function. But is a dependency really necessary or is there an easy way to do it without? Possibly even some defer() tricks, I don't know.
答案1
得分: 5
你不需要外部依赖来实现这个。
你可以使用一个通道并在其上设置超时。
这里有关于这个的文档信息:https://gobyexample.com/timeouts
关键部分是将输入通过通道传递到一个单独的goroutine中,这样主线程就不会阻塞等待。然后,通过在select语句中设置超时,你可以决定等待多长时间来接收通道中的输入。
以下是使用你的帖子作为基础的一个工作示例:
package main
import (
"bufio"
"os"
"log"
"fmt"
"time"
)
var reader = bufio.NewReader(os.Stdin)
func readKey(input chan rune) {
char, _, err := reader.ReadRune()
if err != nil {
log.Fatal(err)
}
input <- char
}
func main() {
input := make(chan rune, 1)
fmt.Println("Checking keyboard input...")
go readKey(input)
select {
case i := <-input:
fmt.Printf("Input : %v\n", i)
case <-time.After(5000 * time.Millisecond):
fmt.Println("Time out!")
}
}
希望对你有帮助!
英文:
You don't need external dependencies to achieve this.
You can use a channel and set a timeout on it.
Here's documentation info about that: https://gobyexample.com/timeouts
The key part is making the input go through the channel in a separate goroutine, so that the main thread does not block waiting. You can then decide how long to wait to receive the input through the channel by setting a timeout in the select clause.
And here's a working sample using your post as a base:
package main
import (
"bufio"
"os"
"log"
"fmt"
"time"
)
var reader = bufio.NewReader(os.Stdin)
func readKey(input chan rune) {
char, _, err := reader.ReadRune()
if err != nil {
log.Fatal(err)
}
input <- char
}
func main() {
input := make(chan rune, 1)
fmt.Println("Checking keyboard input...")
go readKey(input)
select {
case i := <-input:
fmt.Printf("Input : %v\n", i)
case <-time.After(5000 * time.Millisecond):
fmt.Println("Time out!")
}
}
答案2
得分: 0
可能最“go-isch”的方法是使用goroutine和通道。你可以启动两个goroutine,一个等待输入,另一个在超时后休眠。然后,在主goroutine中使用select
语句来检查哪个事件先发生(输入还是超时)。以下是示例代码:
package main
import (
"fmt"
"time"
)
func waitForInput(didInput chan<- bool) {
// 在这里等待有效输入
didInput <- true
}
func main() {
didInput := make(chan bool, 1)
timeout := make(chan bool, 1)
go func() {
time.Sleep(5 * time.Second)
timeout <- true
}()
go waitForInput(didInput)
select {
case <-didInput:
fmt.Println("")
// 在这里继续你的应用程序
case <-timeout:
// 输入超时,退出你的应用程序
}
}
希望对你有帮助!
英文:
Probably the most "go-isch" way to do this is using a goroutine and channels. You start two goroutines, one which waits for input, and one which sleeps until after the timeout period. You then use a select
statement in your main goroutine to check what event happened first (the input, or the timeout). Example code:
package main
import (
"fmt"
"time"
)
func waitForInput(didInput chan<- bool) {
// Wait for a valid input here
didInput <- true
}
func main() {
didInput := make(chan bool, 1)
timeout := make(chan bool, 1)
go func() {
time.Sleep(5 * time.Second)
timeout <- true
}()
go waitForInput(didInput)
select {
case <-didInput:
fmt.Println("")
// Continue your application here
case <-timeout:
// Input timed out, quit your application here
}
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论