当 go 中计时器完成时如何从函数返回?
短信预约 -IT技能 免费直播动态提醒
问题内容
我是刚开始开发玩具测验 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 中计时器完成时如何从函数返回?的详细内容,更多请关注编程网其它相关文章!
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341
当 go 中计时器完成时如何从函数返回?
下载Word文档到电脑,方便收藏和打印~
下载Word文档
猜你喜欢
当 go 中计时器完成时如何从函数返回?
问题内容我是刚开始开发玩具测验 cli 程序。我正在尝试实现一个计时器,以便当计时器结束时,测验就结束了。这是我的初步实现。func StartTimer(quizFinished chan bool, timer *time.Tim
2024-02-06
在Python中使用os.path.exists()函数时返回false如何解决
在Python中使用os.path.exists()函数时返回false如何解决?针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。如下面所示,如果我们用file的readlin
2023-06-14
使用for循环从go函数接收两个返回值时如何有效利用局部变量和临时变量?
来到编程网的大家,相信都是编程学习爱好者,希望在这里学习Golang相关编程知识。下面本篇文章就来带大家聊聊《使用for循环从go函数接收两个返回值时如何有效利用局部变量和临时变量?》,介绍一下,希望对大家的知识积累有所帮助,助力实战开发!
2024-04-04
Go语言如何规定当解析器在 XML 文档中找到处理指令时所调用的函数
Go语言提供xml.Handler接口处理XML事件,当解析器在XML文档中遇到处理指令时,它会调用ProcessingInstruction方法,接收处理指令名称和参数。您可以实现xml.Handler接口并重写ProcessingInstruction方法来自定义处理指令的处理。例如,您可以解析XML文档中的样式表处理指令并加载指定的样式表。通过实现自己的xml.Handler,您可以自定义处理XML处理指令的方式,为Go程序添加灵活性和可定制性。
2024-04-02
Go语言如何规定当解析器在 XML 文档中找到外部实体时被调用的函数
Go语言中,解析器在XML文档中遇到外部实体时,会调用函数:unsafe.AllowedExternalEntities:允许特定公共标识符的外部实体,通过map[string]bool传入。unsafe.AllowExternalEntitiesGlob:使用glob模式允许匹配的外部实体。如果需要禁用外部实体解析,可以使用unsafe.DisallowExternalEntities。允许外部实体存在安全风险,应谨慎使用。
2024-04-02
Go语言如何规定当解析器在 XML 文档中找到符号声明时被调用的函数
Go语言的XML解析器处理符号声明时调用预先注册的函数。这些处理函数负责验证元素、解析属性并创建数据结构。标准库提供了预定义的处理函数,也可以注册自定义函数以处理特定元素。解析器顺序执行这些函数,并在遇到错误时停止解析。
2024-04-02
PHP如何规定当解析器在 XML 文档中找到符号声明时被调用的函数
当PHP解析器在XML文档中遇到符号声明(实体、命名空间、记号)时,它将调用用户定义的处理程序函数。具体有:实体声明处理程序函数:接受实体相关参数,返回外部实体资源句柄或NULL停止解析。字符数据处理程序函数:返回一个字符串或NULL停止解析。符号声明处理程序函数:返回布尔值,TRUE继续解析,FALSE停止解析。通过使用xml_set_external_entity_handler()等函数,可以自定义这些处理程序函数,以灵活处理XML文档中的符号声明。
2024-04-02
Java如何规定当解析器在 XML 文档中找到符号声明时被调用的函数
Java中,当XML解析器遇到实体声明时,它会调用DeclareEntityResolver.resolveEntity方法。该方法解析实体声明,返回包含实体输入流的InputSource对象。实体声明由名称和值组成。解析时,解析器会查找实体定义并替换引用。开发人员可以创建自定义实体解析器来实现自定义逻辑,例如解析外部实体或提供验证。
2024-04-02
Python如何规定当解析器在 XML 文档中找到处理指令时所调用的函数
Python提供了用于处理XML文档中处理指令的函数。默认情况下,processingInstruction()函数在解析器遇到处理指令时被调用。processingInstruction()接收两个参数:目标(指令名称)和数据。开发者可以通过重写ContentHandler类的processingInstruction()方法来自定义处理方式。此外,getxml:content()方法可以检索处理指令的内容。对于高级处理,setEntityResolver()方法允许指定自定义实体解析器来处理处理指令。
2024-04-02
Python如何规定当解析器在 XML 文档中找到外部实体时被调用的函数
Python定义了解析器在XML中遇到外部实体时调用的函数,包括resolve_entity、parser_has_external_dtd和external_entity_resolver。这些函数允许应用程序控制外部实体引用,防止恶意攻击和提供自定义处理。外部实体解析默认禁用,需要开发者显式启用。此外,Python还提供了其他函数和类,如xml.sax.EntityResolver和xml.sax.SAXParseException,用于进一步定制外部实体解析行为和错误处理。
2024-04-02
PHP如何规定当解析器在 XML 文档中找到外部实体时被调用的函数
PHP通过libxml_set_external_entity_loader()函数指定解析XML外部实体时调用的函数。该函数负责加载或解析实体,并返回其内容。外部实体加载器函数接收外部实体URI作为参数,并返回加载的实体内容(成功)或FALSE(失败)。理解PHP如何处理外部实体对于确保安全解析至关重要,尤其是通过受信任的环境中的外部实体加载器函数加载实体。
2024-04-02
Python如何规定当解析器在 XML 文档中找到符号声明时被调用的函数
这篇文章讲解了Python中处理XML符号声明的函数。当解析器在XML文档中遇到符号声明时,它会调用xml.sax模块中的以下函数:start_entity、end_entity、start_notation_decl、end_notation_decl和notation_decl。使用这些函数需要重写SAX解析器类的startDocument和endDocument方法。通过示范代码可以了解如何使用该模块处理XML文档中的符号声明。
2024-04-02
PHP如何规定当解析器在 XML 文档中找到处理指令时所调用的函数
本文解析PHP如何指定处理指令的对应函数。当解析到外部实体时,调用xml_set_external_entity_resolver函数指定外部实体的文件名。内部实体则根据名称调用不同函数,如xml-stylesheet调用xml_set_stylesheet_processing函数。其他处理指令可通过xml_set_processing_instruction_handler函数指定回调函数,此函数接收处理指令名称和值。回调函数遵循特定签名,若涉及处理指令嵌套,需留意处理指令名称和值均为字符串,且PHP
2024-04-02
Java如何规定当解析器在 XML 文档中找到处理指令时所调用的函数
Java处理XML处理指令的机制Java解析器在遇到XML文档中的处理指令时,会调用特定函数。当解析器找到处理指令的开始标签时,它会调用startProcessingInstruction方法。如果指令包含内容,则将其作为参数传递给该方法。解析器还会调用endProcessingInstruction方法来处理指令的结束标签。如果没有注册特定目标名称的处理程序,解析器将使用默认处理程序。遵循最佳实践,谨慎使用处理指令,明确定义目标名称,并考虑使用XML模式进行验证。妥善处理处理指令的内容,以维护文档结构和
2024-04-02
Java如何规定当解析器在 XML 文档中找到外部实体时被调用的函数
Java中,XMLEntityResolver接口用于指定解析器在XML文档中遇到外部实体时调用的函数。自定义实现可控制外部实体访问,提供自定义数据,提高性能。在实现时需注意安全性、性能和兼容性等因素。
2024-04-02
C语言如何规定当解析器在 XML 文档中找到处理指令时所调用的函数
本文介绍了C语言中如何使用函数处理XML文档中的处理指令。当解析器遇到处理指令时,会调用XML处理指令函数规范中的函数。这些函数处理指令的开始和结束,以及指令的内容。步骤包括注册函数、解析XML文档和处理指令。示例代码展示了如何使用这些函数。应用程序包括自定义XML验证、处理DTD和XML转换。
2024-04-02
我们如何克服 CONCAT() 函数的属性,即如果任何一个参数为 NULL,它就会返回 NULL,特别是当我们想要连接列中的值并且任何列的值都为 NULL 时?
上述属性没有什么用处,特别是当我们想要连接列中的值并且任何列的值为 NULL 时。为了克服这个问题,我们可以使用 IFNULL() 函数和 CONCAT() 函数。为了理解它,我们考虑表“Student_name;”中的示例。其中有以下数据
2023-10-22
C语言如何规定当解析器在 XML 文档中找到外部实体时被调用的函数
摘要:本文介绍了C语言中如何使用expat库,为XML解析器设置处理外部实体的函数。外部实体是指存储在外部文件中的数据,当解析器在XML文档中遇到它们时会调用解析器函数。解析器函数负责加载和解析外部数据,返回成功或错误代码。示例代码演示了如何设置和使用外部实体解析器函数,使C语言应用程序可以加载外部数据以进行XML解析。
2024-04-02
C语言如何规定当解析器在 XML 文档中找到符号声明时被调用的函数
C语言规定了当解析器在XML文档中找到符号声明时,将调用xmlSAXDeclHandler函数,其原型为:voidxmlSAXDeclHandler(voiduserData,constxmlCharversion,constxmlCharencoding,constxmlCharstandalone)该函数用于处理符号声明,包括存储版本、编码和独立性信息,执行验证和调整后续解析行为。应用程序可以通过xmlSAXSetDeclHandler注册解析器函数,从而实现可扩展性、可复用性和效率。
2024-04-02