---
title: golang template 库使用教程
date: 2025-10-28
updated: 2026-05-19
category: post
tags:
- go
- tmpl
- 教程
---
> 这个文章目前是用来查看各种关键字和函数如何使用的,需要的话可以看看 [golang template 库入门教程](/post/go-template-intro/) 文章
>
> 文章里的描述可能与实际有出入,请参考官方文档 [text/template - Go Packages](https://pkg.go.dev/text/template#section-documentation)
在我写 [tplate](https://gitea.trle5.xyz/trle5/tplate) 时,我发现网上能找到的 golang template 教程都很分散,不是很方便,于是打算写一篇文章留给自己用
## 运算符
### 逻辑运算符
| 关键字 | 使用方法 | 等价 go 语句 |
| :-----: | ----------- | ------------ |
| **and** | `and C1 C2` | `C1 && C2` |
| **or** | `or C1 C2` | `C1 \|\| C2` |
| **not** | `not C1` | `!C1` |
### 比较运算符
| 关键字 | 使用方法 | 等价 go 语句 | 备注 |
| :---: | ----- | ----- | ----- |
| **eq** | `eq C1 C2` | `C1 == C2` | EQual |
| **ne** | `ne C1 C2` | `C1 != C2` | Not Equal |
| **lt** | `lt C1 C2` | `C1 < C2` | Less Than |
| **le** | `le C1 C2` | `C1 <= C2` | Less than or Equal |
| **gt** | `gt C1 C2` | `C1 > C2` | Greater Than |
| **ge** | `ge C1 C2` | `C1 >= C2` | Greater than or Equal |
**`eq` 关键字可以接受多个参数,例如 `eq C1 C2 C3`,但等价的 go 语句其实是 `C1 == C2 || C1 == C3`**
### 复杂条件式
如果要创建复杂的条件式,有时需要使用括号 `()` 将子条件包裹起来
| 条件式 | 等价 go 语句 |
| ----- | ----- |
| `and C1 (not C2)` | `C1 && !C2` |
| `and (and (gt C1 1) (gt C2 1)) (ne C1 C2)` | `(C1 > 1 && C2 > 1) && C1 != C2` |
| `eq C1 C2 C3 C4` | `C1 == C2 \|\| C1 == C3 \|\| C1 == C4` |
## 关键字
### `if else` 条件判断
可以在模板中判断一些条件,来控制要执行的数据
```js
{{ if .A }}
{{/* 符合 .A 条件时的内容 */}}
{{ else if .B }}
{{/* 不符合 .A 但符合 .B 条件时的内容 */}}
{{ else }}
{{/* 不符合以上全部条件时的内容 */}}
{{ end }}
```
### `range` 遍历
使用 `range` 方法即可遍历数组、切片或 map 键值对,也可以在要遍历的对象为空时进行其他操作
```js
{{ range .Slice }}
{{/* 此时 . 会指向循环中的数据 */}}
当前遍历的值: {{ . }}
{{ else }}
这个切片是空的
{{ end }}
```
#### 在遍历中使用外部值
在 `range` 方法的作用域中,`.` 符号会指向当前遍历的数据,若要在循环中使用外部的值,需要添加 `$` 前缀
```js
{{/* 假设传入的数据中有 Slice 和 Value 这两个变量 */}}
这是 Value 的值: {{ .Value }}
{{ range .Slice }}
当前遍历的值: {{ . }}
循环外部的值: {{ $.Value }}
{{ end }}
```
#### 获取索引或键名
在使用 `range` 方法时可以通过创建变量来获取数组、切片或 map 键值对的索引或键
```js
{{ range $index, $data := .Slice }}
index 变量: {{ $index }}
data 变量: {{ $data }}
当前遍历的值: {{ . }}
{{ end }}
```
创建了变量后依然可以通过 `.` 来直接调用当前遍历的数据
### `index` 获取单个元素
可以使用 `index` 方法来获取数组、切片或 map 键值对中的单个元素
```js
{{ $item_0_in_slice := index .Slice 0 }}
切片中的第 0 个元素为 {{ $item_0_in_slice }}
{{ $item_abc_in_map := index .Map "abc" }}
map 键对值中的 abc 元素为 {{ $item_abc_in_map }}
```
### `break` `continue` 控制循环
在使用 `range` 方法遍历内容时,可以像 go 代码的 for 循环一样使用 `break` 和 `continue` 控制接下来的操作
```js
{{/* 假设 .Numbers 中的数据是 1,2,3,4,5,6,7,8,9,10 */}}
{{ range .Numbers }}
{{ if lt . 5 }}
数字小于 5: {{ . }}
{{ continue }}
{{ end }}
{{ if gt . 2 }}
正在退出循环
{{ break }}
{{ end }}
{{ end }}
现在在循环外
```
### `with` 暂时修改 `.` 指向的数据
有时候只需要使用数据中的某个字段,可以用 `with` 命令来暂时修改 `.` 指向的数据
```js
{{/* 假设传入的数据结构为 .Post.Date */}}
现在是 {{ .Post.Date.Year }} 年 {{ .Post.Date.Month }} 月 {{ .Post.Date.Day }} 日
{{ with .Post.Date }}
{{/* 此时 . 已经指向 .Post.Date,调用 .Year 同等于 .Post.Date.Year */}}
现在是 {{ .Year }} 年 {{ .Month }} 月 {{ .Day }} 日
{{ end }}
```
若要在 `with` 作用域中使用其他外部值,参考 [在遍历中使用外部值](#在遍历中使用外部值)
`with` 命令还可以像 `if else` 那样选择要使用的数据
```js
{{ with .Update.Date }}
{{/* 此时 . 指向 .Update.Date */}}
更新时间 {{ .Year }} 年 {{ .Month }} 月 {{ .Day }} 日
{{ else with .Create.Date }}
{{/* 此时 . 指向 .Create.Date */}}
创建时间 {{ .Year }} 年 {{ .Month }} 月 {{ .Day }} 日
{{ else }}
{{/* 因为没有匹配上面的条件,此时 . 没有发生变化 */}}
未知时间
{{ end }}
```
### `define` `template` 定义和调用模板
可以使用 `define` 命令来预先定义一个模板,再通过 `template` 命令来调用之前定义的模板
```js
{{ define "A" }}
{{/* 模板 A 中的 . 为调用时传入的数据 */}}
在模板 A 中的数据是 {{ . }}
{{ end }}
正在调用模板 A 并传入 "text"
{{ template "A" "text" }}
```
### `block` 重新定义模板并立即调用
`block` 命令其实是一个语法糖,它会定义一个模板并立即调用它
```js
{{/* 首先定义一个名为 template 的模板,它会输出传入的数据 */}}
{{ define "template" }}
传入的数据为 {{ . }}
{{ end }}
{{/* 重新定义 template 模板并传入 . 来执行,它会先输出数据再接着提示语句 */}}
{{ block "template" . }}
{{ . }} 是传入的数据
{{ end }}
{{/* 同等于下方的代码,但需要注意:在一个模板中不允许定义另一个模板 */}}
{{ define "template" }}
{{ . }} 是传入的数据
{{ end }}
{{/* 调用重新定义后的 template 模板并传入 . 来执行*/}}
{{ template "template" . }}
```
为了方便替换使用,go 的 `text/template` 和 `html/template` 库中的模板是允许重复定义的,实际的模板为最后被解析的那个