读书谈技术

如何在 Golang 中使用模板?

2023-08-01  本文已影响0人  技术的游戏

标准模板包的概述

在本文中,我将解释 Go 语言(Golang)的标准模板包的基础知识。这些基础知识包括在 Golang 模板中使用变量、条件语句、遍历变量以及将函数应用于变量。

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

第一个包是最通用的一个——你可以用它来创建所有种类的文本字符串的模板。第二个包更具针对性地用于 HTML——它在处理 HTML 网页环境中的不安全变量时非常方便。

这些包含有各种可以加载、解析和评估模板文本或(HTML 或文本)文件的函数。

例如,你可以使用以下函数:

接下来,我将讨论在 Golang 中创建强大模板的基本构建模块。

外部(程序)变量

你可以从实际的 Go 程序发送变量到你的模板。然后你可以在模板中使用这些变量。

首先,当你希望在模板中渲染特定的操作时,你可以通过在文本字符串中添加双括号 {{}} 来实现这一点。

我们可以利用这个特性来显示你从程序中提供的变量。所以,如果你在双括号中添加一个点,所有的数据字段都将在那里被渲染。

例如,{{.}} 将把你所有的数据字段渲染为一个格式化的字符串。

此外,可以通过指定该字段的名称来访问你的数据的特定字段。

例如,{{ .Title }} 只会将 Title 字段渲染为一个格式化的字符串。

你可以在下面的代码示例中看到这些操作的应用。

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]

在这里运行代码…

在上述代码中,我们首先使用 template.New() 创建一个新的空模板。然后我们使用 Parse() 将一个字符串解析到这个模板中。在这个字符串中,我们在双括号间加入了一个动作。

因为我们在括号之间放了一个点,这向模板渲染器发出了一个信号,即需要在这里渲染提供的变量。

使用 Execute() 来渲染带有变量的模板。第一个参数 (os.Stdout) 是渲染的模板要输出的位置。第二个参数 (Amazing) 是我们希望在模板中渲染的变量。在这种情况下,它只是一个字符串。

我们可以为模板提供的变量,比如说,一个结构体,而不仅仅是一个字符串。在这里,我们创建了一个用于保存书籍数据的结构体。然后,我们可以将其提供给我们之前创建的相同模板。

也可以渲染结构体的单独数据字段。为此,创建一个新的模板字符串。在双括号之间,我们放一个点,后面跟着我们希望渲染的结构体数据字段的名称,而不仅仅是一个点。请注意,这个数据字段是以大写字母写的,表示它是可导出的。

注意 Parse 函数实际上返回两个变量。第一个变量是解析后的模板,第二个是错误消息。在上述示例中,我们不会使用错误消息,所以我们只放一个下划线。

内部(模板)变量

你可以定义内部变量,即只在模板内定义的变量。

下面的模式展示了如何在模板字符串中定义并使用一个变量。首先是定义,然后是使用。内部变量应该以美元符号 ($) 开头。

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

下面是一个简单的例子:

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]

在此处运行代码…

与使用点渲染外部变量不同,在这里我们提到了我们之前在双括号之间定义的变量。

条件语句

以下是条件语句的一般模式:

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

在最后的模式中,你可以根据需要多次使用 {{if else}} 部分,也可以添加一个 {{else}} 部分。以下是第二种模式的一个简单示例:

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...

在此处运行代码…

注意,在上面的例子中,我们也使用了从 Parse() 函数返回的错误消息。如果没有错误,错误消息等于 'nil'。如果有错误,我们可以使用 panic() 函数来处理。

另外,你可以使用以下操作符,而不只是等于 eq(对应 ==):

此外,你还可以直接写入布尔变量,而不是比较语句。

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

在此处运行代码…

循环

在遍历数组、切片或映射时,你可以在模板中使用几种模式。首先,我们来看看最简单的形式。

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

在这里,我们遍历数组、切片或映射(.Var)中的每个变量。在循环的每一步中,只有一个变量可供在循环中使用。

现在,{{.}}不再代表我们模板可用的所有变量,而只代表在循环中可用的那个变量。

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

在此处运行代码...

当你在一堆变量中进行循环时,可以使用以下更复杂的模式:

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

这个模式在你需要在循环中使用变量索引时非常方便。例如,如果你希望输出一个有序的带编号的列表,你可以使用这个模板模式。

注意,这里的变量 $index$element 是在模板内部定义的内部变量。因此,它们也以 ''$' 符号开头。

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

在这里运行代码...

如你所见,这种方法有一个问题。我们从输出中得到的有序列表从0开始。原因是第一个索引总是0。

对于许多应用来说,这并不是我们想要的。我们希望有序列表从1开始。那么,我们如何让每个索引增加1呢?我们需要一个函数来增加给定的变量。

在下一部分,我们将看到如何在模板字符串中运行函数。

在模板中使用函数

在模板中可以使用函数。

为此,你需要将你希望在模板中使用的函数映射到一个关键字。

在下面的例子中,我们将创建一个叫做 add() 的添加函数。我们将使用 template.FuncMap{}FuncMap() 函数内将其添加到函数映射中。

有了 add 函数,我们将能够向 $index 变量添加1,从而增加它。结果将是一个更易读的有序列表。

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

在这里运行代码...

你可以在下面找到一个更复杂的例子。这里我们添加了第二个函数。想法是创建一个CSV风格的输出,但当我们在函数映射中添加“分隔符”时,我们可以选择我们想要的分隔符。

你也可以看到,映射中使用的名称并不是实际函数名称。

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

在这里运行代码…

有一个方便的库,叫做Sprig,它有模板函数映射。你可以在这里找到它。然而,这个库似乎只能和html/template包一起使用。

列表清单

请记住,始终保持学习的态度,并享受编码的乐趣!祝您编码愉快!

如果你喜欢我的文章,点赞,关注,转发!

上一篇 下一篇

猜你喜欢

热点阅读