You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Go语言递归函数中Scanln错误导致的异常行为排查

Go语言递归调用中fmt.Scanln的异常输出原因

当执行以下Go代码时,在命令行输入"wyk"这类非数字字符串,takeInput()函数会在接受新输入前四次打印"How old are you ?";输入数字如19时,递归计数器会增加2次(但不会重复打印提示)。

示例代码

func takeInput() {
    fmt.Println("How old are you ?")
    var age int32
    _, err := fmt.Scanln(&age)
    if err != nil {
        takeInput()
        return
    }
    if age < 18 {
        fmt.Printf("sorry but, you still have %d years to go kid", 18-age)
    } else if age > 18 {
        fmt.Println("well, bottoms up then!")
    }
}

func main() {
    takeInput()
}

输出示例(输入"wyk"时)

How old are you ?
wyk
How old are you ?
How old are you ?
How old are you ?
How old are you ?
_

异常行为的原因

核心问题出在fmt.Scanln的工作机制与递归调用的组合上:

  1. 非数字输入的重复打印问题

    • 当你输入"wyk\n"(实际包含三个字符加换行符),fmt.Scanln(&age)尝试将字符串解析为int32类型,解析失败后,未被解析的输入内容会完整保留在标准输入缓冲区中。
    • 触发递归调用takeInput()后,新的fmt.Scanln会立刻读取缓冲区中残留的字符,每一次读取都因类型不匹配解析失败,进而再次触发递归。
    • 缓冲区中的"w"、"y"、"k"、"\n"四个输入单元,每个都会触发一次解析失败和递归,而每次递归调用takeInput()都会先执行fmt.Println("How old are you ?"),因此会额外打印四次提示。
  2. 数字输入时的计数器异常

    • 输入有效数字如"19\n"时,fmt.Scanln会成功解析出int32类型的19,同时自动丢弃末尾的换行符,不会触发递归逻辑。
    • 你观察到计数器增加2次,大概率是计数器的放置位置有误——比如将计数器放在takeInput函数的入口处(每次调用函数就计数),但实际上有效输入只会触发一次takeInput调用。如果确实出现计数增加2次的情况,可能是终端环境将输入的换行符误判为额外输入,或者你的计数逻辑存在疏漏。

修复思路

要解决重复打印的问题,在解析失败时需要清空标准输入缓冲区中的残留内容,避免后续的Scanln反复读取错误输入。可以在err != nil的分支中添加代码,读取并丢弃缓冲区中剩余的所有字符:

if err != nil {
    // 清空缓冲区中剩余的输入内容
    fmt.Scanln()
    takeInput()
    return
}

内容的提问来源于stack exchange,提问作者Kareem Kasem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 04:10:34