首页 > 解决方案 > Scanf 值在终端中作为命令执行

问题描述

我有一个简单的 go 程序,可以将英里转换为公里:

const kmInMile = 1.609344

func main() {
    var miles float64

    fmt.Print("Enter miles: ")
    fmt.Scanf("%f", &miles)

    fmt.Println(miles)

    km := kmInMile * miles

    fmt.Println(miles, "miles =", km, "km")
}

如果我将“lls”作为输入传递给scanf:

Enter miles: lls

输出是:

0
0 miles = 0 km
alexandrkrivosheev$ ls
hello   main.go

所以输入的第一个字符被采用,所有其他字符都作为命令执行。为什么会发生这种情况,我该如何预防?

完整的终端会话:

alexandrkrivosheev$ ./hello 
Enter miles: lls
0
0 miles = 0 km
alexandrkrivosheev$ ls
hello   main.go
alexandrkrivosheev$ 

标签: go

解决方案


使用“plain fmt.Scanf”时,输入必须与预期格式匹配,即在您的情况下,它必须是有效的浮点数。如果不是,则中止扫描,其余输入保留在控制台的输入缓冲区中,在程序退出后作为下一个命令执行。

要解决此问题,请将标准输入包装到bufio.Readeror中bufio.Scanner

func main() {
    var miles float64

    fmt.Print("Enter miles: ")
    //
    reader := bufio.NewReader(os.Stdin)
    val, err := reader.ReadString('\n')
    if err != nil {
        fmt.Println(err)
        return
    }
    if _, err = fmt.Sscanf(val, "%f", &miles); err != nil {
        fmt.Println(val, err)
        return
    }

    fmt.Println(miles)

    km := kmInMile * miles

    fmt.Println(miles, "miles =", km, "km")
}

这样您就可以从输入中消耗整行并单独处理它。


推荐阅读