ZetCode

Golang fmt.Fscan 函数

最后修改时间 2025 年 5 月 8 日

本教程解释了如何在 Go 中使用 fmt.Fscan 函数。我们将通过实际的读取数据示例涵盖输入扫描基础知识。

fmt.Fscan 函数从 io.Reader 读取格式化输入。它从读取器扫描文本,存储连续的以空格分隔的值。值存储在作为附加参数传递的指针中。

在 Go 中,fmt.Fscan 是 fmt 包扫描函数的一部分。它对于从文件、字符串或网络连接读取结构化数据非常有用。该函数返回成功扫描的项目数。

Fscan 的基本用法

fmt.Fscan 最简单的用法是从字符串读取器读取值。此示例演示了对不同数据类型的基本扫描。
注意:必须将值作为指针传递才能进行修改。

basic_fscan.go
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 从标准输入读取。此示例显示了从控制台进行交互式输入扫描。

stdin_fscan.go
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 通常用于从文件读取结构化数据。此示例演示了从文本文件读取多个记录。

file_fscan.go
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 可以自动解析各种数据格式。此示例显示了扫描不同的数字格式和字符串。

formats_fscan.go
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 可以跨输入的多行进行读取。此示例演示了读取多行输入结构。

multiline_fscan.go
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 时,正确的错误处理至关重要。此示例展示了输入扫描的全面错误检查。

error_fscan.go
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 实现结合使用。此示例展示了从自定义数据源进行扫描。

custom_reader.go
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 包文档

本教程通过从各种源读取格式化输入的实际示例,涵盖了 Go 中的 fmt.Fscan 函数。

作者

我叫 Jan Bodnar,是一名热情的程序员,拥有丰富的编程经验。自 2007 年以来,我一直在撰写编程文章。迄今为止,我已撰写了 1400 多篇文章和 8 本电子书。我在编程教学方面拥有十多年的经验。

列出所有 Golang 教程