在Go语言开发命令行工具时,经常需要程序暂停执行等待用户输入内容,再对输入内容做后续处理,这是命令行交互式程序的核心能力之一。Go语言标准库提供了多个包支持这类需求,不同包的使用场景和特性有所区别。

使用fmt包实现基础输入读取
fmt包是最常用的输入读取方式,适合简单的交互场景,主要通过<Scan>系列函数实现输入读取。这类函数会从标准输入读取内容,默认以空白字符作为分隔符。
fmt.Scan基础用法
fmt.Scan会等待用户输入内容,输入完成后按回车键,函数会读取输入的内容并赋值给对应的变量,返回成功读取的变量数量和可能的错误。
package main
import (
"fmt"
)
func main() {
var name string
var age int
// 提示用户输入内容
fmt.Print("请输入你的姓名和年龄,用空格分隔: ")
// 等待并读取用户输入,按回车后执行读取
n, err := fmt.Scan(&name, &age)
if err != nil {
fmt.Printf("读取输入失败: %vn", err)
return
}
fmt.Printf("成功读取 %d 个值,姓名: %s,年龄: %dn", n, name, age)
}
fmt.Scanln用法
fmt.Scanln和fmt.Scan的区别是,Scanln会在遇到换行符时停止读取,不会读取换行符之后的内容,更适合读取单行输入。
package main
import (
"fmt"
)
func main() {
var input string
fmt.Print("请输入一段文本: ")
// 读取到换行符就停止,不会读取后续内容
_, err := fmt.Scanln(&input)
if err != nil {
fmt.Printf("读取失败: %vn", err)
return
}
fmt.Printf("你输入的内容是: %sn", input)
}
使用bufio包处理复杂输入场景
当需要读取包含空格的完整行输入,或者需要处理输入缓冲时,bufio包是更好的选择。bufio.NewReader可以创建一个带缓冲的读取器,配合<ReadString>方法可以读取完整的一行内容。
读取完整行输入
ReadString方法接收一个分隔符作为参数,会一直读取输入直到遇到该分隔符,返回读取到的内容包含分隔符本身,需要手动处理分隔符。
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("请输入你的个人简介: ")
// 读取到换行符为止,换行符在返回内容中
input, err := reader.ReadString('n')
if err != nil {
fmt.Printf("读取输入失败: %vn", err)
return
}
// 去掉末尾的换行符和可能的回车符
input = strings.TrimSpace(input)
fmt.Printf("你的简介是: %sn", input)
}
处理多次输入交互
bufio读取器可以重复使用,适合需要多次等待用户输入的交互场景,不需要每次都重新创建读取器。
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
for {
fmt.Print("请输入命令(输入exit退出): ")
cmd, err := reader.ReadString('n')
if err != nil {
fmt.Printf("读取失败: %vn", err)
break
}
cmd = strings.TrimSpace(cmd)
if cmd == "exit" {
fmt.Println("程序退出")
break
}
fmt.Printf("你输入的命令是: %sn", cmd)
}
}
两种方式的对比
可以根据实际需求选择合适的输入读取方式,两者的核心差异如下:
| 对比维度 | fmt包方式 | bufio包方式 |
|---|---|---|
| 适用场景 | 简单参数输入,不需要读取带空格的完整行 | 需要读取完整行输入,或者多次交互输入 |
| 分隔符处理 | 默认以空白字符分隔不同变量 | 可以自定义分隔符,默认常用换行符 |
| 缓冲能力 | 无缓冲,直接读取标准输入 | 带缓冲,读取效率更高 |
输入读取的注意事项
- 使用fmt.Scan系列函数时,如果输入的内容和变量类型不匹配,会返回错误,需要做好错误处理。
- bufio.ReadString读取的内容包含分隔符,需要手动去除不需要的分隔符,避免影响后续逻辑。
- 如果程序需要读取密码等敏感输入,标准库没有内置的方法,可以借助第三方库实现不回显输入的功能。
- 在Windows系统中,换行符可能是rn,使用TrimSpace可以同时去除这两种字符,兼容性更好。
无论是使用fmt包还是bufio包,核心逻辑都是让程序阻塞等待标准输入的内容,读取到指定分隔符后继续执行后续代码,开发者可以根据场景灵活选择。
完整示例:简单的命令行问答程序
下面是一个结合两种输入方式的完整示例,实现简单的命令行问答交互:
package main
import (
"bufio"
"fmt"
"os"
"strings"
)
func main() {
var name string
// 使用fmt.Scan读取简单姓名输入
fmt.Print("请输入你的姓名: ")
_, err := fmt.Scan(&name)
if err != nil {
fmt.Printf("读取姓名失败: %vn", err)
return
}
reader := bufio.NewReader(os.Stdin)
fmt.Printf("你好 %s,请输入你对Go语言的评价: ", name)
// 使用bufio读取带空格的评价内容
comment, err := reader.ReadString('n')
if err != nil {
fmt.Printf("读取评价失败: %vn", err)
return
}
comment = strings.TrimSpace(comment)
fmt.Printf("感谢你的评价: %sn", comment)
}