返回

从源码学习 Go 标准库(一):fmt - scan(4)

后端

从源码学习 Go 标准库(一):fmt - scan(4)

在上一篇文章中,我们学习了 scan.go 中一个十分重要的类型:Format 。这一篇文章,我们将学习如何使用 Format 类型去真正地执行扫描操作。

scan.go 文件中实现了两个与扫描操作有关的类型:Scannerscanner

Scanner 类型是一个接口类型,定义了扫描操作最基本的方法:

type Scanner interface {
    Scan(...interface{}) error
    Scanln(...interface{}) error
}

scanner 类型实现了 Scanner 接口,并包含了实际执行扫描操作的具体方法。接下来,我们就逐个学习这些方法。

func (s *scanner) Scan

*func (s scanner) Scan 方法执行一个或多个参数的扫描操作。如果扫描成功,则返回 nil ;否则,返回一个错误。

Scan 方法的具体实现如下:

func (s *scanner) Scan(a ...interface{}) (err error) {
    s.err = nil
    s.lazyInit()
    for i, v := range a {
        err = s.scanOne(v, i == len(a)-1)
        if err != nil {
            return err
        }
    }
    return nil
}

Scan 方法首先会调用 lazyInit 方法,进行一些必要的初始化操作。然后,它会遍历参数列表,依次调用 scanOne 方法对每个参数执行扫描操作。如果扫描操作失败,则 Scan 方法会返回一个错误。

func (s *scanner) Scanln

*func (s scanner) Scanln 方法与 *func (s scanner) Scan 方法类似,唯一的区别在于,Scanln 方法会在扫描操作完成后读取并丢弃输入流中的剩余内容(直到遇到换行符为止)。

Scanln 方法的具体实现如下:

func (s *scanner) Scanln(a ...interface{}) (err error) {
    if err = s.Scan(a...); err == nil {
        return s.skipLine()
    }
    return
}

总结

fmt 包中的扫描操作由 Scanner 接口和 scanner 类型实现。Scanner 接口定义了扫描操作的基本方法,而 scanner 类型则实现了这些方法并包含了实际执行扫描操作的具体方法。

在下一篇文章中,我们将分析完 fmt 包中与扫描操作相关的 scanerror 类型,给整个 fmt 包做个收尾。