2017-05-14 5 views
0

は、これは問題には鍵が読み込まれるため、アプリケーションが常に待機しているが、コンソールGoでキーを読み取るにはどうすればいいですか?x秒以内に何もキーが押されていなければアプリケーションを続行しますか?

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のまたは単位(モジュール)がTurboPascalのがCRTと呼ばれ、readkey機能を有していたていたとして、多分依存関係に引っ張らなければならないことを考えています。しかし、依存関係が本当に必要なのか、それとも簡単な方法がありますか?おそらくいくつかのdefer()トリックさえ、私は知らない。

答えて

0

おそらく、これを行うための最も「行く」方法は、ゴルーチンとチャンネルを使用することです。 2つのゴルーチンを開始します.1つは入力を待機し、もう1つはタイムアウト時間の後までスリープします。その後、メインのゴルーチンのselectステートメントを使用して、最初に発生したイベント(入力またはタイムアウト)を確認します。例コード:

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 
    } 
} 
+0

私はそれについて考えと疑問に思った:(キーボード入力を待つ)readln状態でコマンドラインプログラムを持つことが悪いでなければならないと

そして、ここではベースとしてあなたのポストを使用して作業サンプルですそれから、printlnですでに入ってきて、それをハンマーで止めています(コマンドライン/コンソールはスレッドセーフではありませんか?)。 いくつかのプラットフォームではうまくいくかもしれませんが、キーボード入力を待っている読み取り状態に固執しているコマンドラインプログラム状態にprintlnを投げるのは本当に良い方法です... Windows上で動作し、他のプラットフォームについてはわかりません。しかし、安全かどうかは分かりません!回答ありがとう –

3

これを達成するために外部依存関係は必要ありません。

チャンネルを使用してタイムアウトを設定することができます。

は、ここでそのことについてのドキュメントの情報です:メインスレッドが待機をブロックしないようhttps://gobyexample.com/timeouts

キー部分が入力を行っているが、別のゴルーチンにチャネルを介して行きます。次に、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!") 
    } 
} 
+0

ありがとう!私はそれを試み、報告する。チャンネル、スレッド、ゴルーチンなどがないときに人々は何を使用しましたか?しかし、goにはチャンネルがあるので、それらを使うかもしれません –

+0

彼らはコールバックや反応コード(実際は同じもの)を書きました。 Go&CSPは、よりクリーンな抽象化IMOを提供します。 チャネル(上記)には1つのプレースバッファがあります。最も単純なユースケースでは、これは問題ありません。しかし、タイムアウトで文字を読み込む必要が繰り返されている場合、不要な文字をドロップする方法を設計するには、タイムアウトが間に合わないようにする必要があります。 –

+0

複数のスレッドやルーチンを使用しているのは、スレッドセーフではないコマンドラインコンソールでは良い考えです。読み込み状態(キーボード入力を待っている)になっていれば、その状態になっているのはほぼ法律を破るようなものです。 多分、MS Windowsはこれが運が良かったり、目的に応じて動作することを許していましたが、コンソールモードプログラムはマルチスレッド/ルーチン用ではありませんでした。確かに。私。readlnまたはread状態でコマンド行がその状態になった場合、それがreadlnにあるときにprintln状態に強制するのは悪いようです。 –

関連する問題