Golang中fmt.scan如何处理格式错误的数字

Golang中fmt.scan如何处理格式错误的数字 大家好,

我的代码会请求输入一个数字,然后再请求输入另一个数字。之后,它会按顺序打印这两个数字,一个接一个。

奇怪的是,当我输入的数字中包含其他字符时,会发生一些奇怪的事情。我将在下面展示一些例子。我的问题是,为什么会发生这种情况?为什么完全相同的代码在Windows和Linux上的异常行为会不同?这些例子是在Linux上运行的;在Windows上运行此代码会显示出更奇怪的行为。你需要自己在Windows机器上查看结果。

// 示例1:正常运行 $ go run numbers1.go 输入数字 1: 5 输入数字 2: 7 5 7

// 示例2:第二个数字格式错误 - 这里第二个命令行自动输入了890 $ go run numbers1.go 输入数字 1: 123 输入数字 2: 567q890 123 567 $ 890 bash: 890: command not found… Failed to search for file: Timeout was reached $

// 示例3:第一个数字格式错误 - 这里我只输入了第一个数字,第二个数字自动出现了。 $ go run numbers1.go 输入数字 1: 123q456 输入数字 2: 123 456 $

// 示例4:第一个数字格式错误 - 这里我只输入了第一个数字,第二个数字自动出现了。在“Command not found…”之后,我按了几次回车键,但没有任何反应,所以我按了“CTRL-C”。 $ go run numbers1.go 输入数字 1: 123qwe456 输入数字 2: 123 0 $ e456 bash: e456: command not found…

^C $

package main

import (
    "fmt"
)

func main() {

    var num1 int64
    var num2 int64

    fmt.Print("Enter number 1: ")
    fmt.Scan(&num1)

    fmt.Print("Enter number 2: ")
    fmt.Scan(&num2)

    fmt.Println(num1)
    fmt.Println(num2)
}

更多关于Golang中fmt.scan如何处理格式错误的数字的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

你好,感谢你的回复。

对于第一个数字,你在 printf() 这一行捕获了第一个错误,例如 _, err := fmt.Print("Enter number 1: ")

但对于第二个数字,你却在 fmt.Scan() 这一行捕获错误,_, err = fmt.Scan(&num2)

这是为什么呢? 另外,你是否知道这种奇怪的行为在内部是如何发生的?

更多关于Golang中fmt.scan如何处理格式错误的数字的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


如果左侧有新的标识符,则必须使用赋值运算符 :=。由于 err 在此处是首次声明,因此必须使用 :=。之后,将新值赋给一个已存在的标识符(err)。对于这种情况,必须使用运算符 =

请查阅 https://golang.org/ref/spec#Short_variable_declarationshttps://golang.org/ref/spec#Assignments

我不清楚为什么忽略错误会导致观察到的行为。

永远不要忽略错误。fmt.Scan 的函数签名是:

func Scan(a ...interface{}) (n int, err error)

请务必处理这个错误!

package main

import (
	"fmt"
	"log"
)

func main() {
	var num1 int64
	var num2 int64

	_, err := fmt.Print("Enter number 1: ")
	fmt.Scan(&num1)
	if err != nil {
		log.Panic(err)
	}

	fmt.Print("Enter number 2: ")
	_, err = fmt.Scan(&num2)
	if err != nil {
		log.Panic(err)
	}

	fmt.Println(num1)
	fmt.Println(num2)
}

如果你使用无效的输入运行此代码,一切正常:

❯ go run forum.go
Enter number 1: 2
Enter number 2: 3
2
3
❯ go run forum.go
Enter number 1: a
Enter number 2: b
2020/08/21 07:51:08 expected integer
panic: expected integer

goroutine 1 [running]:
log.Panic(0xc00006cf40, 0x1, 0x1)
	/usr/local/Cellar/go/1.13.1/libexec/src/log/log.go:338 +0xac
main.main()
	/tmp/forum.go:22 +0x2a9
exit status 2

fmt.Scan在遇到格式错误的数字时,会根据空格和换行符进行输入流的分割处理,未成功解析的部分会留在输入缓冲区中,影响后续的读取。Windows和Linux的终端输入处理机制不同,可能导致行为差异。以下是具体分析和改进方案:

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"
    "strings"
)

func main() {
    reader := bufio.NewReader(os.Stdin)

    fmt.Print("Enter number 1: ")
    text1, _ := reader.ReadString('\n')
    num1, err1 := strconv.ParseInt(strings.TrimSpace(text1), 10, 64)
    if err1 != nil {
        fmt.Println("Invalid input for number 1, using default 0")
        num1 = 0
    }

    fmt.Print("Enter number 2: ")
    text2, _ := reader.ReadString('\n')
    num2, err2 := strconv.ParseInt(strings.TrimSpace(text2), 10, 64)
    if err2 != nil {
        fmt.Println("Invalid input for number 2, using default 0")
        num2 = 0
    }

    fmt.Println(num1)
    fmt.Println(num2)
}

对于原代码的异常行为解释:

  1. 当输入567q890时,fmt.Scan解析到q停止,将567存入变量,剩余的890留在缓冲区
  2. 第二个fmt.Scan直接从缓冲区读取890,跳过用户输入
  3. 缓冲区清空后,890被shell当作命令执行,出现command not found

跨平台差异原因:

  • Windows和Linux的换行符不同(\r\n vs \n
  • 终端输入缓冲区的处理机制存在系统级差异
  • 建议使用bufio进行行读取,避免平台依赖问题
回到顶部