12.1 读取用户的输入

我们如何读取用户的键盘(控制台)输入呢?从键盘和标准输入 os.Stdin 读取输入,最简单的办法是使用 fmt 包提供的 Scan...Sscan... 开头的函数。请看以下程序:

示例 12.1 readinput1.go

  1. // 从控制台读取输入:
  2. package main
  3. import "fmt"
  4. var (
  5. firstName, lastName, s string
  6. i int
  7. f float32
  8. input = "56.12 / 5212 / Go"
  9. format = "%f / %d / %s"
  10. )
  11. func main() {
  12. fmt.Println("Please enter your full name: ")
  13. fmt.Scanln(&firstName, &lastName)
  14. // fmt.Scanf("%s %s", &firstName, &lastName)
  15. fmt.Printf("Hi %s %s!\n", firstName, lastName) // Hi Chris Naegels
  16. fmt.Sscanf(input, format, &f, &i, &s)
  17. fmt.Println("From the string we read: ", f, i, s)
  18. // 输出结果: From the string we read: 56.12 5212 Go
  19. }

Scanln() 扫描来自标准输入的文本,将空格分隔的值依次存放到后续的参数内,直到碰到换行。Scanf() 与其类似,除了 Scanf() 的第一个参数用作格式字符串,用来决定如何读取。Sscan... 和以 Sscan... 开头的函数则是从字符串读取,除此之外,与 Scanf() 相同。如果这些函数读取到的结果与您预想的不同,您可以检查成功读入数据的个数和返回的错误。

您也可以使用 bufio 包提供的缓冲读取器 (buffered reader) 来读取数据,正如以下例子所示:

示例 12.2 readinput2.go

  1. package main
  2. import (
  3. "fmt"
  4. "bufio"
  5. "os"
  6. )
  7. var inputReader *bufio.Reader
  8. var input string
  9. var err error
  10. func main() {
  11. inputReader = bufio.NewReader(os.Stdin)
  12. fmt.Println("Please enter some input: ")
  13. input, err = inputReader.ReadString('\n')
  14. if err == nil {
  15. fmt.Printf("The input was: %s\n", input)
  16. }
  17. }

inputReader 是一个指向 bufio.Reader 的指针。inputReader := bufio.NewReader(os.Stdin) 这行代码,将会创建一个读取器,并将其与标准输入绑定。

bufio.NewReader() 构造函数的签名为:func NewReader(rd io.Reader) *Reader

该函数的实参可以是满足 io.Reader 接口的任意对象(任意包含有适当的 Read() 方法的对象,请参考章节 11.8),函数返回一个新的带缓冲的 io.Reader 对象,它将从指定读取器(例如 os.Stdin)读取内容。

返回的读取器对象提供一个方法 ReadString(delim byte),该方法从输入中读取内容,直到碰到 delim 指定的字符,然后将读取到的内容连同 delim 字符一起放到缓冲区。

ReadString 返回读取到的字符串,如果碰到错误则返回 nil。如果它一直读到文件结束,则返回读取到的字符串和 io.EOF。如果读取过程中没有碰到 delim 字符,将返回错误 err != nil

在上面的例子中,我们会读取键盘输入,直到回车键 (\n) 被按下。

屏幕是标准输出 os.Stdoutos.Stderr 用于显示错误信息,大多数情况下等同于 os.Stdout

一般情况下,我们会省略变量声明,而使用 :=,例如:

  1. inputReader := bufio.NewReader(os.Stdin)
  2. input, err := inputReader.ReadString('\n')

我们将从现在开始使用这种写法。

第二个例子从键盘读取输入,使用了 switch 语句:

示例 12.3 switch_input.go

  1. package main
  2. import (
  3. "fmt"
  4. "os"
  5. "bufio"
  6. )
  7. func main() {
  8. inputReader := bufio.NewReader(os.Stdin)
  9. fmt.Println("Please enter your name:")
  10. input, err := inputReader.ReadString('\n')
  11. if err != nil {
  12. fmt.Println("There were errors reading, exiting program.")
  13. return
  14. }
  15. fmt.Printf("Your name is %s", input)
  16. // For Unix: test with delimiter "\n", for Windows: test with "\r\n"
  17. switch input {
  18. case "Philip\r\n": fmt.Println("Welcome Philip!")
  19. case "Chris\r\n": fmt.Println("Welcome Chris!")
  20. case "Ivo\r\n": fmt.Println("Welcome Ivo!")
  21. default: fmt.Printf("You are not welcome here! Goodbye!")
  22. }
  23. // version 2:
  24. switch input {
  25. case "Philip\r\n": fallthrough
  26. case "Ivo\r\n": fallthrough
  27. case "Chris\r\n": fmt.Printf("Welcome %s\n", input)
  28. default: fmt.Printf("You are not welcome here! Goodbye!\n")
  29. }
  30. // version 3:
  31. switch input {
  32. case "Philip\r\n", "Ivo\r\n": fmt.Printf("Welcome %s\n", input)
  33. default: fmt.Printf("You are not welcome here! Goodbye!\n")
  34. }
  35. }

注意:Unix 和 Windows 的行结束符是不同的!

练习

练习 12.1: word_letter_count.go

编写一个程序,从键盘读取输入。当用户输入 ‘S’ 的时候表示输入结束,这时程序输出 3 个数字:
i) 输入的字符的个数,包括空格,但不包括 '\r''\n'
ii) 输入的单词的个数
iii) 输入的行数

练习 12.2: calculator.go

编写一个简单的逆波兰式计算器,它接受用户输入的整型数(最大值 999999)和运算符 +、-、*、/。
输入的格式为:number1 ENTER number2 ENTER operator ENTER --> 显示结果
当用户输入字符 'q' 时,程序结束。请使用您在练习 11.13 中开发的 stack 包。

链接