Maison > développement back-end > Golang > Comment revenir de la fonction lorsque le chronomètre se termine ?

Comment revenir de la fonction lorsque le chronomètre se termine ?

WBOY
Libérer: 2024-02-06 09:45:04
avant
836 Les gens l'ont consulté

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

Contenu de la question

Je viens de commencer à développer un programme cli de test de jouets. J'essaie de mettre en place une minuterie pour que lorsque la minuterie se termine, le quiz soit terminé.

Il s'agit de ma mise en œuvre initiale.

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
}
Copier après la connexion

Édition et mise en œuvre

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)

}
Copier après la connexion

Je continue de recevoir le résultat et l'erreur suivants :

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]:
Copier après la connexion

Je ne comprends pas encore assez bien les chaînes et les goroutines pour comprendre ce qui se passe. Le comportement attendu est que lorsque le minuteur s'arrête, il imprime "Quiz terminé" et envoie une valeur au canal quizFinished, qui est lue dans l'instruction select. Un autre problème que j'ai est que Scanln attendra la saisie de l'utilisateur une fois le quiz terminé. Toute aide serait grandement appréciée !


Réponse correcte


Lorsque vous appelez une fonction Scanln dans la goroutine principale, elle fait une pause et attend la saisie de l'utilisateur. Même si votre timer se termine dans un autre Goroutine et tente d'avertir le Goroutine principal, le Goroutine principal ne répondra pas car il est bloqué par le "Scanner".

C'est pourquoi même si le minuteur se termine, Scanln attend toujours la saisie de l'utilisateur.

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)
}
Copier après la connexion

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:stackoverflow.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal