问题
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:
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:
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
}
}
来源:https://stackoverflow.com/questions/43965556/how-to-read-a-key-in-go-but-continue-application-if-no-key-pressed-within-x-seco