0%

Golang 1.16 新增 embed 包怎么使用

前言

今天 Go 团队很高兴地宣布 Go 1.16 的发布,新增的 embed 包使用新的 //go:embed 指令提供对编译时访问嵌入的文件。

Go 1.16 还添加了 macOS ARM64 的支持(也称为 Apple silicon)。对于苹果新发布的 M1 芯片的 Mac 感兴趣的读者,可以放心购买了。

请注意,Go 1.16 默认需要使用 Go Modules,现在,根据 Go 官方的 2020 Go 开发人员调查,96% 的 Go 开发人员已经切换到了 Go Modules。

Go 1.16 还有许多其他改进和错误修复,包括编译速度提升高达 25% 且内存减少 15%。

本文我们主要来介绍 embed 包的使用方式。

更新历史

2021 年 02月 18日 - 初稿


//go:embed 指令使用方式

使用 //go:embed 指令,需要导入 embed 包,嵌入单个文件,可以使用字符串类型的变量和字节类型切片的变量,并且可以使用 _ 空白导入 embed 包。

FS 类型允许嵌入文件树,例如静态 Web 服务的文件目录,FS 实现了 io/fs 包的 FS 接口,因此,它可以与任何文件系统相关的包一起使用,包括 net/httptext\template,和 html\template

字符串类型模式示例代码:

1
2
//go:embed hello.txt
var s string

字节类型切片模式示例代码:

1
2
//go:embed hello.txt
var b []byte

FS 类型模式示例代码:

1
2
//go:embed hello.txt
var f embed.FS

从以上三段代码中,我们可以看到,在变量声明上方的 //go:embed 指令,指定要嵌入的文件。该指令必须紧接在包含单个变量声明的行之前,变量的类型必须是字符串类型,或者是字节类型的切片,或者是 FS 类型(或 FS 的别名)。

需要注意的是,指令和变量声明之间仅允许空行和使用 // 注释的行。

//go:embed 指令进阶

关于 //go:embed 指令,还有一些值得注意的细节,总结如下:

  1. //go:embed 指令可用于导出变量和未导出变量,具体取决于包是否希望将数据提供给其它包。
  2. //go:embed 指令只能在包作用域中与全局变量一起使用,而不能与局部变量一起使用。
  3. FS 类型模式允许多个路径以空格分隔,字符串类型模式和字节类型的切片模式仅允许匹配单个文件路径。
  4. 路径分隔符是正斜杠(即使在 Windows 系统中)。
  5. 不能包含 ... 或空路径,也不能以斜杠开始或结束。
  6. 如果要匹配当前目录中的所有内容,使用 * 而不是 .

//go:embed 的 FS 类型

FS 是只读的文件集合,通常使用 //go:embed 指令初始化。如果声明时没有 //go:embed 指令,FS 则是一个空文件系统。

FS 是只读值,因此, 可以安全地同时从多个 go 协程使用, 并且安全地将 FS 类型的值分配给对方。

1
2
3
type FS struct {
// contains filtered or unexported fields
}

FS 类型包含三个方法,分别是 Open,ReadDir 和 ReadFile。

  • func (f FS) Open(name string) (fs.File, error) 打开要读取的命名文件,并作为 fs.File 返回它。
  • func (f FS) ReadDir(name string) ([]fs.DirEntry, error) 读取并返回整个命名目录。
  • func (f FS) ReadFile(name string) ([]byte, error) 读取并返回命名文件的内容。

ReadFile 方法的示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package main

import (
"embed"
"fmt"
)

//go:embed hello.txt
var f embed.FS

func main () {
bs, err := f.ReadFile("hello.txt")
if err != nil {
fmt.Println(err)
return
}
fmt.Println(bs)
}

总结

本文主要是介绍 golang v1.16 新增的 embed 包的使用方式,包括新增的 //go:embed 指令和 embed 包的 FS 类型的方法。重点是 //go:embed 指令允许在 Go 应用程序中包含任意文件和目录的内容。

关于 embed 包的更多内容,可以访问源码 /usr/local/go/src/embed/embed.go