我剛開始開發玩具測驗 cli 程式。我正在嘗試實作計時器,以便當計時器結束時,測驗就結束了。
這是我的初步實作。
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 }
編輯實作
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) }
我不斷收到以下輸出和錯誤:
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]:
我對通道和 goroutine 的理解還不夠深入,還無法理解正在發生的事情。預期的行為是當計時器停止時,它會列印“測驗已結束”,並將一個值傳送到 quizFinished 通道,該值在 select 語句中讀取。我遇到的另一個問題是 Scanln 將在測驗結束後等待使用者輸入。如有任何幫助,我們將不勝感激!
當你在主goroutine中呼叫Scanln
函數時,它會暫停並等待使用者輸入。即使你的計時器在另一個 Goroutine 中完成並嘗試通知主 Goroutine,主 Goroutine 也不會響應,因為它被“Scanner”阻止了。
這就是為什麼即使計時器結束,Scanln
仍在等待使用者輸入。
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) }
以上是當 go 中計時器完成時如何從函數返回?的詳細內容。更多資訊請關注PHP中文網其他相關文章!