Golang fmt.Fscan 函数
最后修改时间 2025 年 5 月 8 日
本教程解释了如何在 Go 中使用 fmt.Fscan 函数。我们将通过实际的读取数据示例涵盖输入扫描基础知识。
fmt.Fscan 函数从 io.Reader 读取格式化输入。它从读取器扫描文本,存储连续的以空格分隔的值。值存储在作为附加参数传递的指针中。
在 Go 中,fmt.Fscan 是 fmt 包扫描函数的一部分。它对于从文件、字符串或网络连接读取结构化数据非常有用。该函数返回成功扫描的项目数。
Fscan 的基本用法
fmt.Fscan 最简单的用法是从字符串读取器读取值。此示例演示了对不同数据类型的基本扫描。
注意:必须将值作为指针传递才能进行修改。
package main
import (
"fmt"
"strings"
)
func main() {
input := "42 3.14 hello"
reader := strings.NewReader(input)
var i int
var f float64
var s string
n, err := fmt.Fscan(reader, &i, &f, &s)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d items: %d, %f, %q\n", n, i, f, s)
}
代码从输入字符串中读取一个整数、一个浮点数和一个字符串。该函数返回成功扫描的项数以及任何错误。
从标准输入读取
fmt.Fscan 可以直接使用 os.Stdin 从标准输入读取。此示例显示了从控制台进行交互式输入扫描。
package main
import (
"fmt"
"os"
)
func main() {
var name string
var age int
fmt.Print("Enter your name and age: ")
n, err := fmt.Fscan(os.Stdin, &name, &age)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d items\n", n)
fmt.Printf("Hello %s, you are %d years old\n", name, age)
}
程序等待来自终端的用户输入。值由空格分隔。该函数一直读取,直到填满所有提供的变量。
从文件读取
fmt.Fscan 通常用于从文件读取结构化数据。此示例演示了从文本文件读取多个记录。
package main
import (
"fmt"
"os"
)
type Person struct {
Name string
Age int
}
func main() {
file, err := os.Open("data.txt")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer file.Close()
var people []Person
for {
var p Person
n, err := fmt.Fscan(file, &p.Name, &p.Age)
if err != nil || n != 2 {
break
}
people = append(people, p)
}
fmt.Println("People data:")
for _, p := range people {
fmt.Printf("%s: %d\n", p.Name, p.Age)
}
}
代码从文件中读取姓名-年龄对,直到文件结束 (EOF)。文件中的每一行都应该包含一个姓名和年龄,它们之间用空格分隔。
处理不同的数据格式
fmt.Fscan 可以自动解析各种数据格式。此示例显示了扫描不同的数字格式和字符串。
package main
import (
"fmt"
"strings"
)
func main() {
input := "0x1A 1.5e3 true Golang"
reader := strings.NewReader(input)
var hex int
var sci float64
var flag bool
var lang string
n, err := fmt.Fscan(reader, &hex, &sci, &flag, &lang)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Scanned %d items:\n", n)
fmt.Printf("Hex: %d\n", hex)
fmt.Printf("Scientific: %f\n", sci)
fmt.Printf("Boolean: %t\n", flag)
fmt.Printf("String: %q\n", lang)
}
该函数自动转换十六进制、科学计数法和布尔值。它处理数字的不同基数表示。
读取多行
fmt.Fscan 可以跨输入的多行进行读取。此示例演示了读取多行输入结构。
package main
import (
"fmt"
"strings"
)
func main() {
input := `Product: Laptop
Price: 999.99
InStock: true`
reader := strings.NewReader(input)
var product string
var price float64
var inStock bool
// Skip labels
var label string
fmt.Fscan(reader, &label, &product)
fmt.Fscan(reader, &label, &price)
fmt.Fscan(reader, &label, &inStock)
fmt.Printf("%s: $%.2f (In stock: %t)\n",
product, price, inStock)
}
代码读取分布在多行中的带标签的数据。它会跳过标签,同时将实际值存储在变量中。
Fscan 中的错误处理
在使用 fmt.Fscan 时,正确的错误处理至关重要。此示例展示了输入扫描的全面错误检查。
package main
import (
"fmt"
"strings"
)
func main() {
tests := []string{
"100 200", // valid
"100 abc", // invalid
"100 200 300", // extra
"100", // insufficient
}
for _, input := range tests {
reader := strings.NewReader(input)
var a, b int
n, err := fmt.Fscan(reader, &a, &b)
fmt.Printf("Input: %q\n", input)
fmt.Printf("Scanned %d items\n", n)
if err != nil {
fmt.Println("Error:", err)
} else {
fmt.Printf("Values: %d, %d\n", a, b)
}
fmt.Println("-----")
}
}
代码测试了各种输入场景,并展示了错误是如何报告的。不同类型的输入问题会产生不同的错误条件。
Fscan 的高级用法
fmt.Fscan 可以与自定义的 io.Reader 实现结合使用。此示例展示了从自定义数据源进行扫描。
package main
import (
"fmt"
"io"
)
type Rot13Reader struct {
r io.Reader
}
func (r Rot13Reader) Read(p []byte) (n int, err error) {
n, err = r.r.Read(p)
for i := 0; i < n; i++ {
switch {
case p[i] >= 'A' && p[i] <= 'Z':
p[i] = (p[i]-'A'+13)%26 + 'A'
case p[i] >= 'a' && p[i] <= 'z':
p[i] = (p[i]-'a'+13)%26 + 'a'
}
}
return
}
func main() {
input := "Uryyb Jbeyq"
rot := Rot13Reader{strings.NewReader(input)}
var hello, world string
fmt.Fscan(&rot, &hello, &world)
fmt.Println(hello, world) // Output: Hello World
}
自定义的 Rot13Reader 在扫描前解密文本。这表明 fmt.Fscan 可以与任何 io.Reader 实现配合使用。
来源
本教程通过从各种源读取格式化输入的实际示例,涵盖了 Go 中的 fmt.Fscan 函数。