01
介绍
今天 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
包的使用方式。
//go:embed
指令使用方式
使用 //go:embed
指令,需要导入 embed
包,嵌入单个文件,可以使用字符串类型的变量和字节类型切片的变量,并且可以使用 _
空白导入 embed
包。
FS 类型允许嵌入文件树,例如静态 Web 服务的文件目录,FS 实现了 io/fs
包的 FS 接口,因此,它可以与任何文件系统相关的包一起使用,包括 net/http
,text\template
,和 html\template
。
字符串类型模式示例代码:
//go:embed hello.txt var s string
字节类型切片模式示例代码:
//go:embed hello.txt var b []byte
FS 类型模式示例代码:
//go:embed hello.txt var f embed.FS
从以上三段代码中,我们可以看到,在变量声明上方的 //go:embed
指令,指定要嵌入的文件。该指令必须紧接在包含单个变量声明的行之前,变量的类型必须是字符串类型,或者是字节类型的切片,或者是 FS 类型(或 FS 的别名)。
需要注意的是,指令和变量声明之间仅允许空行和使用 //
注释的行。
03
关于 //go:embed
指令,还有一些值得注意的细节,总结如下:
//go:embed
指令可用于导出变量和未导出变量,具体取决于包是否希望将数据提供给其它包。//go:embed
指令只能在包作用域中与全局变量一起使用,而不能与局部变量一起使用。- FS 类型模式允许多个路径以空格分隔,字符串类型模式和字节类型的切片模式仅允许匹配单个文件路径。
- 路径分隔符是正斜杠(即使在 Windows 系统中)。
- 不能包含
.
或..
或空路径,也不能以斜杠开始或结束。 - 如果要匹配当前目录中的所有内容,使用
*
而不是.
。
04
//go:embed
的 FS 类型
FS 是只读的文件集合,通常使用 //go:embed
指令初始化。如果声明时没有 //go:embed
指令,FS 则是一个空文件系统。
FS 是只读值,因此, 可以安全地同时从多个 go 协程使用, 并且安全地将 FS 类型的值分配给对方。
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 方法的示例代码:
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) }
05
总结
本文主要是介绍 golang v1.16 新增的 embed
包的使用方式,包括新增的 //go:embed
指令和 embed
包的 FS 类型的方法。重点是 //go:embed
指令允许在 Go 应用程序中包含任意文件和目录的内容。
关于 embed
包的更多内容,可以访问源码 /usr/local/go/src/embed/embed.go