如何在 Golang 中使用模板?

標(biāo)準(zhǔn)模板包的概述

在本文中,我將解釋 Go 語(yǔ)言(Golang)的標(biāo)準(zhǔn)模板包的基礎(chǔ)知識(shí)。這些基礎(chǔ)知識(shí)包括在 Golang 模板中使用變量、條件語(yǔ)句、遍歷變量以及將函數(shù)應(yīng)用于變量。

Golang 提供了 text/templatehtml/template 包,以便直接處理模板。

第一個(gè)包是最通用的一個(gè)——你可以用它來(lái)創(chuàng)建所有種類的文本字符串的模板。第二個(gè)包更具針對(duì)性地用于 HTML——它在處理 HTML 網(wǎng)頁(yè)環(huán)境中的不安全變量時(shí)非常方便。

這些包含有各種可以加載、解析和評(píng)估模板文本或(HTML 或文本)文件的函數(shù)。

例如,你可以使用以下函數(shù):

  • 使用 Parse 解析程序內(nèi)部存在的文本字符串。
  • 使用 ParseFiles 加載和解析模板文件。
  • 使用 Execute 通過(guò)特定的數(shù)據(jù)字段將模板渲染到某些輸出。

接下來(lái),我將討論在 Golang 中創(chuàng)建強(qiáng)大模板的基本構(gòu)建模塊。

外部(程序)變量

你可以從實(shí)際的 Go 程序發(fā)送變量到你的模板。然后你可以在模板中使用這些變量。

首先,當(dāng)你希望在模板中渲染特定的操作時(shí),你可以通過(guò)在文本字符串中添加雙括號(hào) {{}} 來(lái)實(shí)現(xiàn)這一點(diǎn)。

我們可以利用這個(gè)特性來(lái)顯示你從程序中提供的變量。所以,如果你在雙括號(hào)中添加一個(gè)點(diǎn),所有的數(shù)據(jù)字段都將在那里被渲染。

例如,{{.}} 將把你所有的數(shù)據(jù)字段渲染為一個(gè)格式化的字符串。

此外,可以通過(guò)指定該字段的名稱來(lái)訪問(wèn)你的數(shù)據(jù)的特定字段。

例如,{{ .Title }} 只會(huì)將 Title 字段渲染為一個(gè)格式化的字符串。

你可以在下面的代碼示例中看到這些操作的應(yīng)用。

package main

import (
    "os"
    "text/template"
)

type Book struct {
    Title     string
    Publisher string
    Year      int
}

func main() {
    t1 := template.New("Template")
    t1, _ = t1.Parse("External variable has the value [{{.}}]\n")
    t1.Execute(os.Stdout, "Amazing")
    b := Book{"The CSound Book", "MIT Press", 2002}
    t1.Execute(os.Stdout, b)
    t2 := template.New("Template")
    t2, _ = t2.Parse("External variable Book has the values [Title: {{.Title}}, Publisher: {{.Publisher}}, Year: {{.Year}}]\n")
    t2.Execute(os.Stdout, b)
}

// Output
// External variable has the value [Amazing]
// External variable has the value [{The CSound Book MIT Press 2002}]
// External variable Book has the values [Title: The CSound Book, Publisher: MIT Press, Year: 2002]

在這里運(yùn)行代碼…

在上述代碼中,我們首先使用 template.New() 創(chuàng)建一個(gè)新的空模板。然后我們使用 Parse() 將一個(gè)字符串解析到這個(gè)模板中。在這個(gè)字符串中,我們?cè)陔p括號(hào)間加入了一個(gè)動(dòng)作。

因?yàn)槲覀冊(cè)诶ㄌ?hào)之間放了一個(gè)點(diǎn),這向模板渲染器發(fā)出了一個(gè)信號(hào),即需要在這里渲染提供的變量。

使用 Execute() 來(lái)渲染帶有變量的模板。第一個(gè)參數(shù) (os.Stdout) 是渲染的模板要輸出的位置。第二個(gè)參數(shù) (Amazing) 是我們希望在模板中渲染的變量。在這種情況下,它只是一個(gè)字符串。

我們可以為模板提供的變量,比如說(shuō),一個(gè)結(jié)構(gòu)體,而不僅僅是一個(gè)字符串。在這里,我們創(chuàng)建了一個(gè)用于保存書(shū)籍?dāng)?shù)據(jù)的結(jié)構(gòu)體。然后,我們可以將其提供給我們之前創(chuàng)建的相同模板。

也可以渲染結(jié)構(gòu)體的單獨(dú)數(shù)據(jù)字段。為此,創(chuàng)建一個(gè)新的模板字符串。在雙括號(hào)之間,我們放一個(gè)點(diǎn),后面跟著我們希望渲染的結(jié)構(gòu)體數(shù)據(jù)字段的名稱,而不僅僅是一個(gè)點(diǎn)。請(qǐng)注意,這個(gè)數(shù)據(jù)字段是以大寫字母寫的,表示它是可導(dǎo)出的。

注意 Parse 函數(shù)實(shí)際上返回兩個(gè)變量。第一個(gè)變量是解析后的模板,第二個(gè)是錯(cuò)誤消息。在上述示例中,我們不會(huì)使用錯(cuò)誤消息,所以我們只放一個(gè)下劃線。

內(nèi)部(模板)變量

你可以定義內(nèi)部變量,即只在模板內(nèi)定義的變量。

下面的模式展示了如何在模板字符串中定義并使用一個(gè)變量。首先是定義,然后是使用。內(nèi)部變量應(yīng)該以美元符號(hào) ($) 開(kāi)頭。

{{$var:=`value`}}  ... {{$var}} ...

下面是一個(gè)簡(jiǎn)單的例子:

package main

import (
    "os"
    "text/template"
)

func main() {
    t, _ := template.New("Template").Parse("{{$var:=2150}}Internal variable has the value [{{$var}}]")
    t.Execute(os.Stdout, nil)
}

// Output:
// Internal variable has the value [2150]

在此處運(yùn)行代碼…

與使用點(diǎn)渲染外部變量不同,在這里我們提到了我們之前在雙括號(hào)之間定義的變量。

條件語(yǔ)句

以下是條件語(yǔ)句的一般模式:

{{if [..]}} if-part {{end}}
{{if [..]}} if-part {{else}} else-part {{end}}
{{if [..]}} if-part {{if else}} if-else-part {{end}}

在最后的模式中,你可以根據(jù)需要多次使用 {{if else}} 部分,也可以添加一個(gè) {{else}} 部分。以下是第二種模式的一個(gè)簡(jiǎn)單示例:

package main

import (
    "os"
    "text/template"
)

func main() {
    t, err := template.New("Template").Parse("{{if eq . `filler`}}This is filler...{{else}}It's something else...{{end}}\n")
    if err != nil {
        panic(err)
    }
    t.Execute(os.Stdout, "filler")
}

// Output:
// This is filler...

在此處運(yùn)行代碼…

注意,在上面的例子中,我們也使用了從 Parse() 函數(shù)返回的錯(cuò)誤消息。如果沒(méi)有錯(cuò)誤,錯(cuò)誤消息等于 'nil'。如果有錯(cuò)誤,我們可以使用 panic() 函數(shù)來(lái)處理。

另外,你可以使用以下操作符,而不只是等于 eq(對(duì)應(yīng) ==):

  • 非等于 ne(對(duì)應(yīng) !=)
  • 小于 lt(對(duì)應(yīng) <)
  • 小于等于 le(對(duì)應(yīng) <=)
  • 大于 gt(對(duì)應(yīng) >)
  • 大于等于 ge(對(duì)應(yīng) >=)

此外,你還可以直接寫入布爾變量,而不是比較語(yǔ)句。

package main

import (
    "os"
    "text/template"
)

func main() {
    t, _ := template.New("Template").Parse("{{if .}}This is true.{{else}}This is false.{{end}}\n")
    t.Execute(os.Stdout, false)
}

// Output:
// This is false

在此處運(yùn)行代碼…

循環(huán)

在遍歷數(shù)組、切片或映射時(shí),你可以在模板中使用幾種模式。首先,我們來(lái)看看最簡(jiǎn)單的形式。

{{range .Var}}
    {{.}}
{{end}}

在這里,我們遍歷數(shù)組、切片或映射(.Var)中的每個(gè)變量。在循環(huán)的每一步中,只有一個(gè)變量可供在循環(huán)中使用。

現(xiàn)在,{{.}}不再代表我們模板可用的所有變量,而只代表在循環(huán)中可用的那個(gè)變量。

package main

import (
    "os"
    "text/template"
)

func main() {
    computerList := []string{"Arduino", "Raspberri Pi", "NVidia Jetson Nano"}
    t, err := template.New("Template").Parse("My favorite computers are:\n{{range .}}{{.}}\n{{end}}\n")
    if err != nil {
        panic(err)
    }
    t.Execute(os.Stdout, computerList)
}

// Output:
// My favorite computers are:
// Arduino
// Raspberri Pi
// NVidia Jetson Nano

在此處運(yùn)行代碼...

當(dāng)你在一堆變量中進(jìn)行循環(huán)時(shí),可以使用以下更復(fù)雜的模式:

{{range $index, $element := . }} 
    {{$index}} ... {{$element}} ...
{{end}}

這個(gè)模式在你需要在循環(huán)中使用變量索引時(shí)非常方便。例如,如果你希望輸出一個(gè)有序的帶編號(hào)的列表,你可以使用這個(gè)模板模式。

注意,這里的變量 $index$element 是在模板內(nèi)部定義的內(nèi)部變量。因此,它們也以 ''$' 符號(hào)開(kāi)頭。

package main

import (
    "os"
    "text/template"
)

func main() {
    dishesList := []string{"Enciladas con Pollo", "Hot&Spicy Pizza", "Spaghetti Bolognese"}
    t, err := template.New("Template").Parse("My favorite dishes are:\n{{range $index, $item:=.}}{{$index}}) {{$item}}\n{{end}}\n")
    if err != nil {
        panic(err)
    }
    t.Execute(os.Stdout, dishesList)
}

// Output
// My favorite dishes are:
// 0) Enciladas con Pollo
// 1) Hot&Spicy Pizza
// 2) Spaghetti Bolognese

在這里運(yùn)行代碼...

如你所見(jiàn),這種方法有一個(gè)問(wèn)題。我們從輸出中得到的有序列表從0開(kāi)始。原因是第一個(gè)索引總是0。

對(duì)于許多應(yīng)用來(lái)說(shuō),這并不是我們想要的。我們希望有序列表從1開(kāi)始。那么,我們?nèi)绾巫屆總€(gè)索引增加1呢?我們需要一個(gè)函數(shù)來(lái)增加給定的變量。

在下一部分,我們將看到如何在模板字符串中運(yùn)行函數(shù)。

在模板中使用函數(shù)

在模板中可以使用函數(shù)。

為此,你需要將你希望在模板中使用的函數(shù)映射到一個(gè)關(guān)鍵字。

在下面的例子中,我們將創(chuàng)建一個(gè)叫做 add() 的添加函數(shù)。我們將使用 template.FuncMap{}FuncMap() 函數(shù)內(nèi)將其添加到函數(shù)映射中。

有了 add 函數(shù),我們將能夠向 $index 變量添加1,從而增加它。結(jié)果將是一個(gè)更易讀的有序列表。

package main

import (
    "os"
    "text/template"
)

func add(a, b int) int {
    return a + b
}
func main() {
    dishesList := []string{"Enciladas con Pollo", "Hot&Spicy Pizza", "Spaghetti Bolognese"}
    t, err := template.New("Template").Funcs(template.FuncMap{"add": add}).Parse("My favorite dishes are:\n{{range $index, $item:=.}}{{add $index 1}}) {{$item}}\n{{end}}\n")
    if err != nil {
        panic(err)
    }
    t.Execute(os.Stdout, dishesList)
}

// Output:
// My favorite dishes are:
// 1) Enciladas con Pollo
// 2) Hot&Spicy Pizza
// 3) Spaghetti Bolognese

在這里運(yùn)行代碼...

你可以在下面找到一個(gè)更復(fù)雜的例子。這里我們添加了第二個(gè)函數(shù)。想法是創(chuàng)建一個(gè)CSV風(fēng)格的輸出,但當(dāng)我們?cè)诤瘮?shù)映射中添加“分隔符”時(shí),我們可以選擇我們想要的分隔符。

你也可以看到,映射中使用的名稱并不是實(shí)際函數(shù)名稱。

package main

import (
    "os"
    "text/template"
)

func add(a, b int) int {
    return a + b
}
func delimiter(s string) func() string {
    return func() string {
        return s
    }
}
func main() {
    dishesList := []string{"Enciladas con Pollo", "Hot&Spicy Pizza", "Spaghetti Bolognese"}
    tmpl := "Index{{dl}}Dish\n{{range $index, $item:=.}}{{add $index 1}}{{dl}}{{$item}}\n{{end}}\n"
    funcMap := template.FuncMap{"add": add, "dl": delimiter(",")}
    t, _ := template.New("Template").Funcs(funcMap).Parse(tmpl)
    t.Execute(os.Stdout, dishesList)
}

// Output:
// Index,Dish
// 1,Enciladas con Pollo
// 2,Hot&Spicy Pizza
// 3,Spaghetti Bolognese

在這里運(yùn)行代碼…

有一個(gè)方便的庫(kù),叫做Sprig,它有模板函數(shù)映射。你可以在這里找到它。然而,這個(gè)庫(kù)似乎只能和html/template包一起使用。

列表清單

請(qǐng)記住,始終保持學(xué)習(xí)的態(tài)度,并享受編碼的樂(lè)趣!祝您編碼愉快!

如果你喜歡我的文章,點(diǎn)贊,關(guān)注,轉(zhuǎn)發(fā)!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容