ZetCode

Golang fmt.Fscanln 函数

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

本教程将解释如何在 Go 中使用 fmt.Fscanln 函数。我们将通过实际示例介绍输入扫描基础知识,包括从各种来源读取格式化输入。

fmt.Fscanln 函数从 io.Reader 读取,并将空格分隔的值扫描到连续的参数中。它在换行符处停止扫描,并且在最后一个项目之后,必须有一个换行符或 EOF。

在 Go 中,fmt.Fscanln 类似于 fmt.Scanln,但它适用于任何 io.Reader。它对于从文件、网络连接或自定义读取器读取结构化输入非常有用。

Fscanln 的基本用法

fmt.Fscanln 最简单的用法是从字符串读取器读取值。此示例演示了基本的输入扫描。
注意:值必须用空格分隔,并以换行符结尾。

basic_fscanln.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    input := "John 25 true\n"
    reader := strings.NewReader(input)
    
    var name string
    var age int
    var active bool
    
    n, err := fmt.Fscanln(reader, &name, &age, &active)
    
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Printf("Read %d values: %s, %d, %t\n", n, name, age, active)
}

代码从字符串中读取三种不同的类型。该函数返回成功扫描的项目数以及遇到的任何错误。

从标准输入读取

fmt.Fscanln 可以直接使用 os.Stdin 从标准输入读取。此示例展示了交互式输入扫描。

stdin_fscanln.go
package main

import (
    "fmt"
    "os"
)

func main() {
    fmt.Println("Enter your name and age (separated by space):")
    
    var name string
    var age int
    
    n, err := fmt.Fscanln(os.Stdin, &name, &age)
    
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Printf("Hello %s! You are %d years old.\n", name, age)
    fmt.Printf("Successfully read %d values.\n", n)
}

程序等待用户输入并读取两个值。Fscanln 要成功完成,输入后的换行符是必需的。

从文件读取

fmt.Fscanln 通常用于从文件中读取结构化数据。此示例演示了文件输入扫描。

file_fscanln.go
package main

import (
    "fmt"
    "os"
)

func main() {
    file, err := os.Open("data.txt")
    if err != nil {
        fmt.Println("Error opening file:", err)
        return
    }
    defer file.Close()
    
    var product string
    var price float64
    var quantity int
    
    _, err = fmt.Fscanln(file, &product, &price, &quantity)
    if err != nil {
        fmt.Println("Error reading file:", err)
        return
    }
    
    fmt.Printf("Product: %s\nPrice: $%.2f\nQuantity: %d\n", 
        product, price, quantity)
}

代码从包含产品数据的文件中读取一行。请记住处理文件打开错误并在完成后关闭文件。

处理多行

要读取多行,请在循环中使用 fmt.Fscanln。此示例展示了如何逐行处理结构化数据。

multiline_fscanln.go
package main

import (
    "bufio"
    "fmt"
    "strings"
)

func main() {
    data := `Alice 25
Bob 30
Charlie 35`
    
    scanner := bufio.NewScanner(strings.NewReader(data))
    
    for scanner.Scan() {
        line := scanner.Text()
        reader := strings.NewReader(line)
        
        var name string
        var age int
        
        _, err := fmt.Fscanln(reader, &name, &age)
        if err != nil {
            fmt.Println("Error:", err)
            continue
        }
        
        fmt.Printf("%s is %d years old\n", name, age)
    }
}

代码将 bufio.Scanner 与行读取结合使用,并将 Fscanln 与行解析结合使用。这种模式对于结构化文本处理非常高效。

读取不同的数据类型

fmt.Fscanln 可以自动处理各种 Go 类型。此示例演示了从输入中读取混合数据类型。

mixed_types.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    input := "Go 1.21 true 42\n"
    reader := strings.NewReader(input)
    
    var lang string
    var version float64
    var compiled bool
    var year int
    
    n, err := fmt.Fscanln(reader, &lang, &version, &compiled, &year)
    if err != nil {
        fmt.Println("Error:", err)
        return
    }
    
    fmt.Printf("Read %d values:\n", n)
    fmt.Println("Language:", lang)
    fmt.Println("Version:", version)
    fmt.Println("Compiled:", compiled)
    fmt.Println("Year:", year)
}

该函数会自动将输入字符串转换为目标变量类型。如果输入与预期类型不匹配,则会返回转换错误。

错误处理

在使用 fmt.Fscanln 时,正确处理错误至关重要。此示例显示了全面的错误检查。

error_handling.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    testCases := []string{
        "100 200\n",
        "100\n",
        "100 abc\n",
        "100 200 300\n",
    }
    
    for _, input := range testCases {
        reader := strings.NewReader(input)
        var a, b int
        
        n, err := fmt.Fscanln(reader, &a, &b)
        fmt.Printf("Input: %q\n", input)
        
        if err != nil {
            fmt.Println("  Error:", err)
        } else {
            fmt.Printf("  Read %d values: %d, %d\n", n, a, b)
        }
    }
}

代码测试了各种输入场景,并展示了 Fscanln 在不同输入下的行为。始终检查返回计数和错误。

读取到切片中

虽然 fmt.Fscanln 需要固定参数,但我们可以通过一些额外的代码读取到切片中。此示例演示了该技术。

slice_reading.go
package main

import (
    "fmt"
    "strings"
)

func main() {
    input := "5 10 15 20 25\n"
    reader := strings.NewReader(input)
    
    var nums []int
    for {
        var num int
        n, err := fmt.Fscanln(reader, &num)
        
        if n == 0 || err != nil {
            break
        }
        
        nums = append(nums, num)
    }
    
    fmt.Println("Read numbers:", nums)
    fmt.Println("Sum:", sum(nums))
}

func sum(nums []int) int {
    total := 0
    for _, n := range nums {
        total += n
    }
    return total
}

代码读取数字,直到遇到错误。当您无法预测值的数量时,这种模式对于读取可变长度的输入非常有用。

来源

Go 包文档

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

作者

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

列出所有 Golang 教程