日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

Go庫text與template包使用示例詳解_Golang

作者:小馬別過河 ? 更新時間: 2023-01-14 編程語言

場景

現在的項目,基本都是前后端分離,后端只要提供Json等格式的數據就行。在這個背景下,模板渲染這個功能備受冷落,很少會在項目中用到。

雖然在 http 服務中,模板解析不常用,但日常開發中,巧妙利用模板生成代碼,能使我們開發事半功倍。比如:

  • 使用模板初始化項目。比如我們每次新建一個 http 服務,可能都需要 promethue 監控、日志等模塊。每次都實現一遍不現實,(或者 copy 別的項目),我們可以寫好模板,支持自定義項目名,初始化新項目。
  • 生成代碼。比如之前文章提到的 mockery,就是解析 interface 的語法樹,利用模板生成 Mock 對象。

text/template 包

基本用法

text/template提供的接口和html/template包一樣,只不過后者會為 html 格式的輸出做轉義,避免攻擊。

text/template 用法很簡單:

func main() {
	// 要注入的變量
	type Inventory struct {
		Material string
		Count    uint
	}
	sweaters := Inventory{"wool", 17}
	// 模板內容, {{.xxx}} 格式的都會被注入的變量替換
	text := `{{.Count}} items are made of {{.Material}}`
	TestTemplate(text, sweaters)
}
func TestTemplate(text string, data interface{}) {
	// 初始化,解析
	tmpl, err := template.New("test").Parse(text)
	if err != nil {
		panic(err)
	}
	// 輸出到 os.Stdout
	err = tmpl.Execute(os.Stdout, data)
	if err != nil {
		panic(err)
	}
}

結果輸出如下:

17 items are made of wool

其中,Execute的聲明為:

// 第一個參數是輸出的接口,第二個參數是要注入的數據
func (t *Template) Execute(wr io.Writer, data interface{}) error

第二個參數 data 是 interface{},類型不限,可以是:

  • 結構體,屬性在模板中用 {{.Field}} 表示。
  • map,value 在模板中用 {{.Key}} 表示。
  • 其他簡單類型(int、string等),在模板中用{{.}}表示。
	// data 為 map
	m := map[string]interface{}{"Material": "wool", "Count": 17}
	TestTemplate(`{{.Count}} items are made of {{.Material}}`, m) // 輸出:17 items are made of wool
	// data 為 int,{{.}} 代表注入的變量
	TestTemplate(`{{.}} items`, 17) // 輸出:17 items

另外,我們也可以使用 template.Must 來檢測返回的 error, 如果 error 不為 nil 則 panic。也就是說下面的代碼:

tmpl, err := template.New("test").Parse(text)
if err != nil {
  panic(err)
}

等價于:

tmpl := template.Must(template.New("test").Parse(txt))

我們重點介紹一下,Parse的參數(代碼中的text變量),也就是模板的內容。

模板語法

模板里{{xxx}}格式稱之為 Action,默認以{{}}作為分界符,表示模板的流程控制、或者變量。

空白字符

如果 Action 以 {{- 開頭,會把 action 左邊的空白字符刪除,這里的空白字符包括空格、換行、tab等。同理,-}}會把右邊的空白字符刪除。如:

	d := struct{ Name string }{"Neil"}
	TestTemplate(`name = {{.Name}} ;`, d) // 輸出:name = Neil ;
	// 刪除掉 .Name 左邊的空格
	TestTemplate(`name = {{- .Name}} ;`, d) // 輸出:name =Neil ;
	// 刪除掉 .Name 右邊的空格
	TestTemplate(`name = {{.Name -}} ;`, d) // 輸出:name = Neil;
	// 刪除掉 .Name 兩邊的空格
	TestTemplate(`name = {{- .Name -}} ;`, d) // 輸出:name =Neil;

常用 Action

備注,格式為 {{/*xxxx*/}},注意備注的內容是可以換行的。

text := `{{/*this is a comment*/}} name : {{.}} `
TestTemplate(text, "Neil")
// 輸出:
//  name : Neil 

遍歷,可以使用 range 關鍵字。遍歷的變量只能是 slice、array、map 或者 channel。

下面代碼中的 {{.}} 代表 .MapContent 的元素。

d1 := struct{ MapContent []string }{MapContent: []string{"neil", "garmen", "ray"}}
text = "{{range .MapContent}}{{.}} {{end}}"
TestTemplate(text, d1)
// 輸出:
// neil garmen ray

注意,這時候的.不是代表d1變量,如果希望在 range 塊里面使用d1, 需要使用 {{$.}}

另外也可以使用自定義變量來遍歷:

text = "{{range $i,$v := .MapContent}}{{$i}}=>{{$v}} {{end}}"
TestTemplate(text, d1)
// 輸出
// 0=>neil 1=>garmen 2=>ray

if-else,變量為零值,或者空 slice、array、map,就相當于是 false。

text = `{{if .Name}}emtpy{{else}}not empty{{end}}`
d = struct{ Name string }{"Neil"}
TestTemplate(text, d) // 輸出: empty

if 還可以配合 and、or、not 使用:

// .condition1 && .condition2 
if and .condition1 .condition2 
// .condition1 ||  .condition2 
if or .condition1 .condition2 
// !.condition
if not .condition

with-else, 和if基本一樣。區別是,with 作用域的 {{.}} 代表 with 參數,而不是全局的 {{.}}.

text = "{{with .Name}}{{.}}{{else}}empty{{end}}"
d = struct{ Name string }{"Neil"}
TestTemplate(text, d) // 輸出: Neil

自定義模板,使用 define 定義,template 引用。

text = `{{define "T1"}}ONE{{end}}
{{define "T2"}}TWO{{end}}
{{define "T3"}}{{template "T1"}} {{template "T2"}}{{end}}
{{template "T3"}}`
TestTemplate(text, nil)
// 輸出: ONE TWO

函數

模板提供了一些函數,如上文的andornot。比如下文的 index 函數,打印 MapContent 的 index 為 1 的元素。

text = `{{index .MapContent 1}}`
d1 = struct{ MapContent []string }{MapContent: []string{"neil", "garmen", "ray"}}
TestTemplate(text, d1)
// 輸出:garmen

另外,函數還能以管道的方式,一個函數的結果,作為另一個參數的輸入,如 {{func1 args | func2 }}。還有可以使用自定義函數,詳情可以查看官方文檔:pkg.go.dev/text/templa…。

總結

text/template 功能挺多,本文只是大致介紹一下,詳情還得移步官網

原文鏈接:https://juejin.cn/post/7174364757435088933

欄目分類
最近更新