【问题标题】:Why doesn't fmt.Scanf in Go wait for user input?为什么 Go 中的 fmt.Scanf 不等待用户输入?
【发布时间】:2022-02-24 13:27:02
【问题描述】:

我正在阅读 Caleb Doxsey 的围棋书,我有两个关于 fmt.Scanf http://www.golang-book.com/4 的问题

我想知道为什么程序在第二次 Scanf 之后没有停止并等待用户输入?以及如何测试用户是否输入了整数和/或没有留空?

package main

import (
"fmt"
//"math"
)


// compute square roots by using Newton's method

func main() {

var x float64           //number to take square root
var y float64           //this is the guess
var q float64           //this is the quotient
var a float64           //this is the average


// how do check if the user entered a number
fmt.Print("Enter a number to take its square root: ")
var inputSquare float64
fmt.Scanf("%f", &inputSquare)

// why doesn't program stop after 
// the Print statement and wait
// for user input?
fmt.Print("Enter first guess ")
var inputGuess float64
fmt.Scanf("%f", &inputGuess)

//x = 2
x = inputSquare
y = inputGuess

for i := 0; i < 10; i++ {   //set up the for loop for iterations
    q = x/y                 //compute the quotient; x and y are given
    a = (q + y) / x         //compute the average       
    y = a                   //set the guess to the average              
}                           //for the next loop


fmt.Println("y --> ", y)
//fmt.Println("Sqrt(2)", math.Sqrt(2))
}

【问题讨论】:

  • 它适合我。我猜这是一个行尾问题。如果你在 Windows 上运行,行尾通常用 '\r\n' 表示,而在 Mac OS X 和 Linux(我测试过的地方)上,它只是 '\n'。我的猜测是 Go 可能正在读取 '\r' ,将其视为行尾,并将 '\n' 留在流中。所以当你再次调用 fmt.Scanf 时,缓冲区中已经有东西了,不需要阻塞。不过,这只是一个疯狂的猜测。
  • 好的。任何建议如何解决它?这就是我在 Windows 命令行中运行的内容: c:\Go\src\play\exercise>go run loop_exercise.go 输入一个数字来取其平方根: 2 Enter first guess y --> +Inf
  • 如果您使用 Scanf 调用显式读取换行符会发生什么?喜欢“fmt.Scanf("%f\n", &amp;inputGuess)”?或者,您可以在每次读取后刷新标准输入。我不知道去哪里告诉你去哪里找一个 Flush 函数。
  • 是的,添加\n 解决了这个问题。

标签: go


【解决方案1】:

更新:原为fixed almost a decade agoThe docs for fmt 现在阅读

在所有扫描函数中,回车后紧跟换行符被视为普通换行符(\r\n 与 \n 含义相同)。

如果您仍然遇到扫描错误,mind that it isn't your IDE's fault


它是 Issue 5391: fmt: Scanf 在 Windows 的行尾拒绝 \r\n

作为一种解决方法并检查有效输入,写入,

var inputSquare float64
n, err := fmt.Scanf("%f\n", &inputSquare)
if err != nil || n != 1 {
    // handle invalid input
    fmt.Println(n, err)
}

var inputGuess float64
n, err = fmt.Scanf("%f\n", &inputGuess)
if err != nil || n != 1 {
    // handle invalid input
    fmt.Println(n, err)
}

解决方法是"%f\n" 格式字符串中的换行符。

fmt

func Scanf

func Scanf(format string, a ...interface{}) (n int, err error)

Scanf 扫描从标准输入读取的文本,存储连续的 由空格分隔的值到由 格式。它返回成功扫描的项目数。

这是一个完整的工作程序:

package main

import (
    "fmt"
)

// compute square roots by using Newton's method
func main() {
    var x float64 //number to take square root
    var y float64 //this is the guess
    var q float64 //this is the quotient
    var a float64 //this is the average

    fmt.Print("Enter a number to take its square root: ")
    var inputSquare float64
    n, err := fmt.Scanf("%f\n", &inputSquare)
    if err != nil || n != 1 {
        // handle invalid input
        fmt.Println(n, err)
        return
    }

    fmt.Print("Enter first guess ")
    var inputGuess float64
    n, err = fmt.Scanf("%f\n", &inputGuess)
    if err != nil || n != 1 {
        // handle invalid input
        fmt.Println(n, err)
        return
    }

    x = inputSquare
    y = inputGuess
    for i := 0; i < 10; i++ {
        q = x / y       // compute the quotient; x and y are given
        a = (q + y) / x // compute the average
        y = a           // set the guess to the average
    }
    fmt.Printf("sqrt(%g) = %g\n", x, y)
}

输出:

Enter a number to take its square root: 2.0
Enter first guess 1.0
sqrt(2) = 1.414213562373095

我在 Windows 7 上使用 Go 1.1.1:

C:\>go version
go version go1.1.1 windows/amd64  

【讨论】:

  • 谢谢。 fmt.Scanf() 是否返回错误?我假设,n 是输入,errn, err := fmt.Scanf("%f\n", &amp;inputSquare)中可能出现的错误消息@这是正确的吗?
  • 查看我修改后的答案。 n 是成功扫描的项目数,err 报告扫描期间遇到的任何错误。因此,如果出现错误或扫描的项目数量不是您所期望的 (err != nil || n != 1),请采取措施处理错误。但是,如果一切顺利 (err == nil &amp;&amp; n == 1),则可以从 *inputSquare 中读取作为浮点数 (float64) 的有效输入。在您的代码中,您丢弃了nerr,这就是您没有注意到错误的原因。
  • 我一定是做错了什么。如果我使用错误处理部分 n, err := fmt.Scanf("f\n", &amp;inputSquare) // pick up the error if err != nil || n != 1 { fmt.Println(n, err) 运行程序,我会得到“0 输入与格式不匹配”​​(例如,我输入 inputSquare 的 2.0)如果我注释掉错误处理,一切正常!我做错了什么?
  • 我已经修改了我的答案以提供一个完整的工作程序。运行程序会得到什么输出?
猜你喜欢
  • 1970-01-01
  • 2021-01-19
  • 2018-06-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-12
  • 2015-05-15
  • 1970-01-01
  • 2021-12-11
相关资源
最近更新 更多