Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to cancel fmt.Scanf after a certain timeout?

Tags:

go

I have a very simple command line utility and at the end of it I'm waiting for a user to hit the enter key to end the program:

fmt.Scanf("\n") // wait for hitting the enter key to end the program

Now I want to change it and if the enter key hasn't been hit for some time, I want to cancel Scanf and do something else. Is it possible to cancel waiting for user's input?

like image 309
vitr Avatar asked Jun 11 '18 12:06

vitr


1 Answers

You can simply create a channel and launch a goroutine which does the fmt.Scanf("\n") and then writes something to the channel. Then select between that channel and time.After(3 * time.Second).

Here's a solution:

package main

import (
    "fmt"
    "time"
    "os"
)

func main() {
    // Rest of the program...

    ch := make(chan int)

    go func() {
        fmt.Scanf("\n")
        ch <- 1
    }()

    select {
    case <-ch:
        fmt.Println("Exiting.")
        os.Exit(0)
    case <-time.After(3 * time.Second):
        fmt.Println("Timed out, exiting.")
    }
}

NOTE: as pointed out by @Fabian and @YotKay in the comments, this will "leak" a goroutine (meaning it will remain running until the process exits) if the timeout expires and the user does not enter anything. This is still fine in a situation in which you have to either wait for input or exit the program, but not advisable in other cases, since it's not possible to "cancel" goroutines from the outside.

like image 179
Marco Bonelli Avatar answered Sep 17 '22 22:09

Marco Bonelli