Wie komme ich von der Funktion zurück, wenn der Timer in Go abgelaufen ist?

WBOY
Freigeben: 2024-02-06 09:45:04
nach vorne
777 Leute haben es durchsucht

当 go 中计时器完成时如何从函数返回?

Frageninhalt

Ich habe gerade mit der Entwicklung eines Spielzeugtest-CLI-Programms begonnen. Ich versuche, einen Timer zu implementieren, sodass das Quiz beendet ist, wenn der Timer abgelaufen ist.

Dies ist meine erste Implementierung.

func StartTimer(quizFinished chan bool, timer *time.Timer) {
    // Start timer
    <-timer.C
    fmt.Println("\nQuiz has ended")
    quizFinished <- true
    return
}

func askQuestions(timer *time.Timer, questions []string, answers []string) []string {
    var input string
    var userAnswers []string
    quizFinished := make(chan bool)

    fmt.Println("Starting Quiz...")

    go StartTimer(quizFinished, timer)

    for index, element := range questions {
        select {
        case <-quizFinished:
            fmt.Println("Quiz has ended")
            return userAnswers
        default:
            fmt.Printf("Question %d: %s? ", index+1, element)
            fmt.Scanln(&input)
            userAnswers = append(userAnswers, input)
        }
    }

    return userAnswers
}
Nach dem Login kopieren

Redaktion und Umsetzung

package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "os"
    s "strings"
    "time"
)

func readFileData(fileName string) (questions []string, answers []string) {
    file, err := os.Open(fileName)
    if err != nil {
        log.Fatalf("failed reading data from file: %v", err)
    }

    defer file.Close()

    scanner := bufio.NewScanner(file)
    for scanner.Scan() {
        questionAndAnswer := s.Split(scanner.Text(), ",")
        question, answer := questionAndAnswer[0], questionAndAnswer[1]
        questions = append(questions, question)
        answers = append(answers, answer)
    }
    return questions, answers
}

func askQuestions(timer *time.Timer, questions []string) []string {
    var input string
    var userAnswers []string = make([]string, 0, len(questions))
    quizFinished := make(chan bool, 1)

    fmt.Println("Starting Quiz...")

    go func() {
        <-timer.C
        fmt.Println("\nquiz over...")
        quizFinished <- true
    }()

    for index, element := range questions {
        fmt.Printf("Question %d: %s? ", index+1, element)
        answerCh := make(chan string, 1)
        go func() {
            fmt.Scanln(&input)
            answerCh <- input
        }()

        select {
        case <-quizFinished:
            return userAnswers
        case answer := <-answerCh:
            userAnswers = append(userAnswers, answer)
        }
    }

    return userAnswers
}

func main() {
    fileNamePtr := flag.String("filename", "problems.csv", "Specify a file name to read in")
    quizTimePtr := flag.Int("time", 5, "Specify how long the quiz should take")
    flag.Parse()

    timer := time.NewTimer(time.Duration(*quizTimePtr) * time.Second)
    questions, answers := readFileData(*fileNamePtr)

    // var userAnswers = askQuestions(timer, questions, answers)
    var userAnswers = askQuestions(timer, questions)
    correctAnswers := 0
    incorrectAnswers := 0

    for i := 0; i < len(answers); i++ {
        if userAnswers[i] == answers[i] {
            correctAnswers++
        } else {
            incorrectAnswers++
        }
    }

    grade := float32(correctAnswers) / float32(len((questions)))
    fmt.Printf("Total Questions: %d \n", len(questions))
    fmt.Printf("Total Correct Answers: %d \n", correctAnswers)
    fmt.Printf("Total Incorrect Answers: %d \n", incorrectAnswers)
    fmt.Printf("Grade: %.0f%% \n", grade*100)

}
Nach dem Login kopieren

Ich erhalte ständig die folgende Ausgabe und Fehlermeldung:

Starting Quiz...
Question 1: 5+5? 10
Question 2: 1+1?
Quiz has ended
2
Returning from quiz...
panic: runtime error: index out of range [2] with length 2

goroutine 1 [running]:
Nach dem Login kopieren

Ich verstehe Kanäle und Goroutinen noch nicht gut genug, um zu verstehen, was vor sich geht. Das erwartete Verhalten besteht darin, dass der Timer beim Stoppen „Quiz beendet“ ausgibt und einen Wert an den Kanal „quizFinished“ sendet, der in der SELECT-Anweisung gelesen wird. Ein weiteres Problem, das ich habe, ist, dass Scanln nach dem Ende des Quiz auf Benutzereingaben wartet. Jede Hilfe wäre sehr dankbar!


Richtige Antwort


Wenn Sie eine Scanln-Funktion in der Haupt-Goroutine aufrufen, hält sie an und wartet auf Benutzereingaben. Selbst wenn Ihr Timer in einer anderen Goroutine abläuft und versucht, die Haupt-Goroutine zu benachrichtigen, antwortet die Haupt-Goroutine nicht, da sie vom „Scanner“ blockiert wird.

Deshalb wartet Scanln auch dann noch auf Benutzereingaben, wenn der Timer abgelaufen ist.

package main

import (
    "fmt"
    "time"
)

func askQuestions(timer *time.Timer, questions []string) []string {
    var input string
    var userAnswers []string
    quizFinished := make(chan bool, 1)

    fmt.Println("start quiz...")
    go func() {
        <-timer.C
        fmt.Println("\nquiz over...")
        quizFinished <- true
    }()

    for index, element := range questions {
        fmt.Printf("question %d: %s? ", index+1, element)
        answerCh := make(chan string, 1)

        go func() {
            fmt.Scanln(&input)
            answerCh <- input
        }()

        select {
        case <-quizFinished:
            fmt.Println("exit quiz...")
            return userAnswers
        case answer := <-answerCh:
            userAnswers = append(userAnswers, answer)
        }
    }

    return userAnswers
}

func main() {
    timer := time.NewTimer(10 * time.Second)
    questions := []string{"5+5", "1+1", "8+3"}
    responses := askQuestions(timer, questions)
    fmt.Println("answer:", responses)
}
Nach dem Login kopieren

Das obige ist der detaillierte Inhalt vonWie komme ich von der Funktion zurück, wenn der Timer in Go abgelaufen ist?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Quelle:stackoverflow.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage
Über uns Haftungsausschluss Sitemap
Chinesische PHP-Website:Online-PHP-Schulung für das Gemeinwohl,Helfen Sie PHP-Lernenden, sich schnell weiterzuentwickeln!