Go1.16 新特性:一文快速上手 Go embed

如有任何問題或建議,歡迎及時交流和碰撞。個人公衆號是 【腦子進煎魚了】,GitHub 地址: https://github.com/eddycjy

你們好,我是煎魚。git

在之前,不少從其餘語言轉過來 Go 語言的同窗會問到,或是踩到一個坑。就是覺得 Go 語言所打包的二進制文件中會包含配置文件的聯同編譯和打包。github

image.png

結果每每一把二進制文件挪來挪去,就沒法把應用程序運行起來了。由於沒法讀取到靜態文件的資源。安全

沒法將靜態資源編譯打包進二進制文件的話,一般會有兩種解決方法:架構

  • 第一種是識別這類靜態資源,是否須要跟着程序走。
  • 第二種就是考慮將其打包進二進制文件中。

第二種狀況的話,Go 之前是不支持的,你們就會去借助各類花式的開源庫,例如:go-bindata/go-bindata 來實現。函數

但從在 Go1.16 起,Go 語言自身正式支持了該項特性,今天咱們將經過這篇文章快速瞭解和學習這項特性。微服務

基本使用

演示代碼:學習

import _ "embed"

//go:embed hello.txt
var s string

func main() {
    print(s)
}

咱們首先在對應的目錄下建立了 hello.txt 文件,而且寫入文本內容 「吃煎魚」。spa

在代碼中編寫了最爲核心的 //go:embed hello.txt 註解。註解的格式很簡單,就是 go:embed 指令聲明,外加讀取的內容的地址,可支持相對和絕對路徑。設計

輸出結果:code

吃煎魚

讀取到靜態文件中的內容後自動賦值給了變量 s,而且在主函數中成功輸出。

而針對其餘的基礎類型,Go embed 也是支持的:

//go:embed hello.txt
var s string

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

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

func main() {
    print(s)
    print(string(b))

    data, _ := f.ReadFile("hello.txt")
    print(string(data))
}

輸出結果:

吃煎魚
吃煎魚
吃煎魚

咱們同時在一個代碼文件中進行了多個 embed 的註解聲明。

而且針對 string、slice、byte、fs 等多種類型進行了打包,也不須要過多的處理,很是便利。

拓展用法

除去基本用法完,embed 自己在指令上也支持多種變形:

//go:embed hello1.txt hello2.txt
var f embed.FS

func main() {
    data1, _ := f.ReadFile("hello1.txt")
    fmt.Println(string(data1))

    data2, _ := f.ReadFile("hello2.txt")
    fmt.Println(string(data2))
}

在指定 go:embed 註解時能夠一次性多個文件來讀取,而且也能夠一個變量多行註解:

//go:embed hello1.txt 
//go:embed hello2.txt
var f embed.FS

也能夠經過在註解中指定目錄 helloworld,再對應讀取文件:

//go:embed helloworld
var f embed.FS

func main() {
    data1, _ := f.ReadFile("helloworld/hello1.txt")
    fmt.Println(string(data1))

    data2, _ := f.ReadFile("helloworld/hello2.txt")
    fmt.Println(string(data2))
}

同時既然可以支持目錄讀取,也能支持貪婪模式的匹配:

//go:embed helloworld/*
var f embed.FS

可能會有小夥伴注意到,embed.FS 也能調各種文件系統的接口,其實本質是 embed.FS 實現了 io/fs 接口。

只讀屬性

在 embed 所提供的 FS 中,咱們能夠發現其都是打開和只讀方法:

type FS
    func (f FS) Open(name string) (fs.File, error)
    func (f FS) ReadDir(name string) ([]fs.DirEntry, error)
    func (f FS) ReadFile(name string) ([]byte, error)

根據此也能夠肯定 embed 所打包進二進制文件的內容只容許讀取,不容許變動。

更抽象來說就是在編譯期就肯定了 embed 的內容,在運行時不容許修改,保證了一致性。

總結

經過 Go1.16 正式提供的 embed 特性,能夠實現原生就支持靜態資源文件的嵌入。總體以下:

  • 在功能上:可以將靜態資源嵌入二進制文件中,在運行時能夠打開和讀取相關的打包後的靜態文件。
  • 在安全上:是在編譯期編譯嵌入,在運行時不支持修改。
  • 在使用上:

    • 支持單文件讀取:go:embed hello.txt
    • 支持多文件讀取:go:embed hello1.txtgo:embed hello2.txt
    • 支持目錄讀取:go:embed helloworld
    • 支持貪婪匹配:go:embed helloworld/*

總的來說,Go1.16 embed 特性很好的填補了 Go 語言在打包靜態文件資源的一塊原生空白領域。同時也說明了 Go 官方的確在不斷地吸取社區的一些良好的想法和經驗。

個人公衆號

分享 Go 語言、微服務架構和奇怪的系統設計,歡迎你們關注個人公衆號和我進行交流和溝通。

最好的關係是互相成就,各位的點贊就是煎魚創做的最大動力,感謝支持。

相關文章
相關標籤/搜索