终端执行应用程序中输入的超时

I am trying to make a terminal golang application, where a user has 4 seconds to input something. If he inputted something faster, print result and ask him input again for 4 seconds.

If a user will not return input in 4 seconds, the program must write time out and ask him input again.

My code does this, but only once. After the first timeout it won't return any result even if a user was faster that 4 seconds. I cannot figure out why this is so.

The code

package main

import (
    "bufio"
    "fmt"
    "log"
    "os"
    "time"
)

var (
    result string
    err    error
)

func getInput(input chan string) {
    in := bufio.NewReader(os.Stdin)
    result, err := in.ReadString('
')
    if err != nil {
        log.Fatal(err)
    }

    input <- result
}

func main() {
    for {
        fmt.Println("input something")
        input := make(chan string, 1)
        go getInput(input)

        select {
        case i := <-input:
            fmt.Println("result")
            fmt.Println(i)
        case <-time.After(4000 * time.Millisecond):
            fmt.Println("timed out")
        }
    }
}

The output:

input something
123
result
123

input something
2
result
2

input something
timed out
input something
2
timed out
input something
timed out
input something

The problem has to do with the way you're getting the user's input. On a timeout you spawn a new go routine asking for input, but the old one that you had spawned previously is still there grabbing input and sending it to a channel that no one is listening to any more.

Changing it to something like this would fix the problem:

func getInput(input chan string) {
    for {
        in := bufio.NewReader(os.Stdin)
        result, err := in.ReadString('
')
        if err != nil {
            log.Fatal(err)
        }

        input <- result
    }
}

func main() {
    input := make(chan string, 1)
    go getInput(input)

    for {
        fmt.Println("input something")

        select {
        case i := <-input:
            fmt.Println("result")
            fmt.Println(i)
        case <-time.After(4000 * time.Millisecond):
            fmt.Println("timed out")
        }
    }
}