9.2 使用内置包
标准的Go语言代码库中包含了大量的包,并且在安装 Go 的时候多数会自动安装到系统中。我们可以在“$GOROOT/src/pkg”目录中查看这些包。
9.2.1 常用内置包简介
在Go语言中,提供了如下所示的常用内置包。
- fmt:包实现了格式化的标准输入输出,这与C语言中的 printf 和 scanf 类似。其中的 fmt.Printf() 和 fmt.Println() 是开发者使用最为频繁的函数。
- io:提供了原始的 I/O 操作界面,主要的任务是对 os 包这样的原始的 I/O 进行封装,增加一些其他相关,使其具有抽象功能用在公共的接口上。
- bufio:通过对 io 包的封装,提供了数据缓冲功能,能够一定程度减少大块数据读写带来的开销。在 bufio 各个组件内部都维护了一个缓冲区,数据读写操作都直接通过缓存区进行。当发起一次读写操作时,会首先尝试从缓冲区获取数据,只有当缓冲区没有数据时,才会从数据源获取数据更新缓冲。
- sort:提供了用于对切片和用户定义的集合进行排序的功能。
- strconv:提供了将字符串转换成基本数据类型,或者从基本数据类型转换为字符串的功能。
- os:提供了不依赖平台的操作系统函数接口,设计像 Unix 风格,但错误处理是 go 风格,当 os 包使用时,如果失败后返回错误类型而不是错误数量。
- sync:实现多线程中锁机制以及其他同步互斥机制。
- flag:提供命令行参数的规则定义和传入参数解析的功能。绝大部分的命令行程序都需要用到这个包。
- encoding/json:提供了对 JSON 的基本支持,比如从一个对象序列化为 JSON 字符串,或者从 JSON 字符串反序列化出一个具体的对象等。
- html/template:主要实现了 web 开发中生成 html 的 template 的一些函数。
- net/http:提供 HTTP 相关服务,主要包括 http 请求、响应和 URL 的解析,以及基本的 http 客户端和扩展的 http 服务。通过 net/http 包,只需要数行代码,即可实现一个爬虫或者一个 Web 服务器,这在传统语言中是无法想象的。
- reflect:实现了运行时反射,允许程序通过抽象类型操作对象。通常用于处理静态类型 interface{} 的值,并且通过 Typeof 解析出其动态类型信息,通常会返回一个有接口类型 Type 的对象。
- os/exec:提供了执行自定义 linux 命令的相关实现。
- strings:与包 bytes 中的函数接口功能基本一致,提供了处理字符串的一些函数集合,包括合并、查找、分割、比较、后缀检查、索引、大小写处理等等。
- bytes:提供了对字节切片进行读写操作的一系列函数。字节切片处理的函数比较多,分为基本处理函数、比较函数、后缀检查函数、索引函数、分割函数、大小写处理函数和子切片处理函数等。
- log:主要用于在程序中输出日志。
9.2.2 包strconv
strconv是Go语言标准库中的一个包,用于将字符串和基本数据类型之间进行转换。在包strconv中主要提供了如下所示的内置函数:
- Atoi():将字符串转换为整数。
- ParseInt():将字符串转换为任意进制的整数。
- FormatInt():将整数转换为字符串。
- ParseFloat():将字符串转换为浮点数。
- FormatFloat():将浮点数转换为字符串。
请看下面的实例,能够读取用户输入的文本,并将其转换为一个整数。如果用户输入的是无效的整数,则程序应该输出错误消息并退出。
实例9-1:将用户输入的文本转换为整数(源码路径:Go-codes\9\strconvert.go)
实例文件strconvert.go的具体实现代码如下所示。
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
fmt.Print("Please enter an integer: ")
for scanner.Scan() {
input := scanner.Text()
num, err := strconv.Atoi(input)
if err != nil {
fmt.Printf("'%s' is not a valid integer\n", input)
os.Exit(1)
} else {
fmt.Printf("You entered %d\n", num)
break
}
}
}
在上述代码中,使用标准库中的包bufio从标准输入中读取用户输入。然后尝试将输入字符串转换为整数。如果转换失败,则程序输出错误消息并退出;否则,它将打印输入的整数并退出。例如下面的执行结果:
Please enter an integer: foo
'foo' is not a valid integer
在这说明用户输入了一个无效的字符串,因此程序输出了错误消息并退出。
再例如下面的执行结果,这说明用户输入了一个有效的整数,因此程序打印了该整数并退出。
Please enter an integer: 42
You entered 42
总之,包strconv是一个非常实用的工具,可以用于将字符串和基本数据类型之间进行转换。它在处理用户输入等需要将字符串转换为数字的场景中特别有用。
9.2.3 包reflect
reflect是 Go 语言标准库中的一个非常重要的包,用于在运行时动态地检查变量类型和值,并进行操作。reflect提供了许多方法来获取有关变量的信息,例如变量的类型、值、字段、方法等等。下面列出了包reflect中的常用内置函数和具体功能:
- TypeOf():获取变量的类型。
- ValueOf():获取变量的值。
- Kind():获取变量的种类。
- NumField():获取结构体中字段的数量。
- Field():获取结构体中指定索引的字段。
- CanSet():判断是否可以设置变量的值。
- SetValue():设置变量的值。
请看下面的实例,功能是使用包reflect获取并修改结构体中的字段。
实例9-2:获取并修改结构体中的字段(源码路径:Go-codes\9\jian.go)
实例文件jian.go的具体实现代码如下所示。
package main
import (
"fmt"
"reflect"
)
type Person struct {
Name string
Age int
Gender string
}
func main() {
p := Person{"Alice", 25, "Female"}
// 获取 p 变量的值和类型
value := reflect.ValueOf(p)
typ := reflect.TypeOf(p)
// 打印值和类型
fmt.Println("Value:", value)
fmt.Println("Type:", typ)
// 遍历结构体中的字段
for i := 0; i < value.NumField(); i++ {
field := value.Field(i)
fieldName := typ.Field(i).Name
fieldValue := field.Interface()
fmt.Printf("%s: %v\n", fieldName, fieldValue)
}
// 修改结构体中的字段
nameField := value.FieldByName("Name")
if nameField.CanSet() {
nameField.SetString("Bob")
fmt.Printf("Name changed to %s\n", p.Name)
}
}
对上述代码的具体说明如下:
- 首先,创建了一个名为 Person 的结构体,表示人物属性。然后它创建了一个 Person 类型变量 p 并初始化。
- 然后,使用包reflect获取变量p的值和类型,并遍历结构体中的字段以打印它们的名称和值。
- 接下来,使用方法FieldByName()获取指向 "Name" 字段的值,并使用方法CanSet()检查是否可以修改该字段的值。
- 最后,使用 SetString 方法将 "Name" 字段的值更改为 "Bob" 并输出修改后的名字。最后,使用方法FieldByName()获取结构体中 "Name" 字段的值,并使用方法SetString()将其更改为 "老管"。注意,在修改前需要检查字段是否可以设置,否则会出错。
执行后会输出:
Value: {Alice 25 Female}
Type: main.Person
Name: Alice
Age: 25
Gender: Female
Name changed to 老管
注意:在这个实例中,必须使用 &p 来传递结构体变量的地址给方法reflect.ValueOf(),以便能够修改变量的值。另外,在修改字段之后,在下一行中输出修改后的名字。