最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Go语言模板语法举例详细说明
时间:2026-08-11 11:35:50 编辑:袖梨 来源:一聚教程网
Go语言模板语法举例详细说明并不只看表面做法,关键还要理解相关条件、限制和后续影响。
引言
目标:吃透 {{ }} 里的动作(action):输出、变量、条件、循环、with、管道与内置函数。这是后面嵌套/继承/Gin 的语法基础。

1. 模板语法总览
Go 模板里,普通文本原样输出;逻辑都写在 action 中:
{{ ... }}常见类别:
| 类别 | 例子 | 作用 |
|---|---|---|
| 输出 | {{.Name}} | 打印值 |
| 注释 | {{/* ... */}} | 不输出 |
| 变量 | {{$x := .}} | 绑定到 $x |
| 条件 | {{if}}...{{end}} | 分支 |
| 循环 | {{range}}...{{end}} | 遍历 |
| 改上下文 | {{with}}...{{end}} | 临时切换 . |
| 管道 | {{. | printf "%s"}} | 函数链式处理 |
| 模板调用 | {{template "x" .}} | 嵌套(下节细讲) |
2. 点(dot).:当前上下文
. 是模板里最重要的概念
Execute(w, data)时,根上下文.=data- 进入
range/with后,.可能变成「当前元素」 - 离开
range/with后,.恢复
例子
type Product struct {Name stringPrice int}type Page struct {ShopName stringItems []Product}店铺:{{.ShopName}}{{range .Items}} <!-- 这里的 . 是 Product --> 商品:{{.Name}},价格:{{.Price}}{{end}}<!-- 这里 . 又回到 Page -->再次显示店铺:{{.ShopName}}如果在 range 里还想访问外层的 ShopName,不能写 {{.ShopName}}(因为 . 已是 Product),要用变量把外层存起来
3. 输出与注释
3.1 输出字段 / 键 / 方法
{{.Name}} <!-- struct 导出字段 -->{{.User.Email}} <!-- 链式字段 -->{{index .Map "k"}} <!-- map 取值的稳妥写法 -->{{.FullName}} <!-- 无参方法,方法名需导出 -->方法示例:
type User struct {First stringLast string}func (u User) FullName() string {return u.First + " " + u.Last}{{.FullName}}注意:方法若返回 (value, error),模板执行时若 error != nil 会失败
3.2 注释
{{/* 这是注释,不会出现在最终 HTML 里 */}}注释不能嵌套,内容里也不要随便写 */}} 这类结束符
3.3 什么时候会「空输出」?
访问不到的字段、nil 指针的字段等,在默认设置下可能输出为空,或在 missingkey 等选项下报错。调试时建议先把数据结构打印出来,确认字段名大小写一致
4. 变量:$name
用 $ 定义模板变量:
{{$title := .Title}}<h1>{{$title}}</h1>为什么需要变量?
最经典场景:range 里访问外层数据
{{$shop := .ShopName}}{{range .Items}} <li>{{$shop}} - {{.Name}}</li>{{end}}也可以在 range 时直接接收索引和元素:
{{range $i, $item := .Items}} <li>#{{$i}} {{$item.Name}}</li>{{end}}赋值与重新绑定
{{$x := 1}}{{$x = 2}} <!-- 重新赋值(Go 1.11+ 模板支持) -->入门更常见的是 := 定义一次后只读使用
作用域
变量一般在定义它的 {{if}}/{{range}}/{{with}}/...{{end}} 块内有效;在块外可能不可见(以你使用的 Go 版本与定义位置为准)。实践建议:在需要的最小范围内定义。
5. 条件:if/else/else if
{{if .LoggedIn}} <p>欢迎,{{.Name}}</p>{{else}} <p>请先登录</p>{{end}}什么算「真」?
模板把下列值视为 false(不进入 if 主体):
false- 数字
0 - 空字符串
"" nil- 空的 array / slice / map / chan
其它一般视为 true。
多分支
{{if eq .Role "admin"}} 管理员面板{{else if eq .Role "editor"}} 编辑面板{{else}} 普通用户{{end}}比较函数(很常用)
这些是内置函数,不是操作符写成 ==:
| 函数 | 含义 |
|---|---|
eq | == |
ne | != |
lt | < |
le | <= |
gt | > |
ge | >= |
{{if gt .Age 18}} 成年{{end}}{{if eq .Status "ok" "ready"}} <!-- eq 支持多参数:与任一相等即为真 --> 可用{{end}}逻辑与或非:
{{if and .A .B}} ... {{end}}{{if or .A .B}} ... {{end}}{{if not .Hidden}} ... {{end}}6.with:临时切换上下文
with 有两个作用:
- 判断值是否为真
- 若为真,在块内把
.换成这个值
{{with .Profile}} <p>城市:{{.City}}</p> <p>签名:{{.Bio}}</p>{{else}} <p>用户未填写资料</p>{{end}}等价心智模型:
如果 Profile 有值: 进入块,且 . = Profile否则: 走 else
with+ 变量
{{with $p := .Profile}} {{$p.City}}{{end}}ifvswith
| if | with | |
|---|---|---|
是否切换 . | 否 | 是 |
| 适合 | 纯条件判断 | 深入嵌套结构体字段 |
很多人写 {{if .Profile}}{{.Profile.City}}{{end}},用 with 更干净。
7.range:遍历
可遍历:slice、array、map、channel。
7.1 基础遍历
<ul>{{range .Items}} <li>{{.Name}} - ¥{{.Price}}</li>{{else}} <li>暂无商品</li>{{end}}</ul>else 分支在集合为空时执行,非常适合空状态 UI。
7.2 索引与元素
{{range $index, $product := .Items}} <tr> <td>{{$index}}</td> <td>{{$product.Name}}</td> </tr>{{end}}遍历 map:
{{range $key, $value := .Labels}} <span>{{$key}}={{$value}}</span>{{end}}注意:map 的遍历顺序不稳定(随机),若要稳定展示,应在 Go 里先排好序再传给模板,或传 []struct{Key, Value}。
7.3 range 里修改了.
{{range .Items}} <!-- . 是元素 --> {{.Name}}{{end}}若只写 {{range .Items}} 不接变量,元素就绑定到 .。
8. 管道(pipeline)
管道用 |,把左边结果作为右边函数的最后一个参数。
{{.Name | printf "用户:%s"}}等价于:printf("用户:%s", .Name)。
多级管道
{{.Name | printf "%s" | html}}(在 html/template 中,上下文感知转义通常已自动发生;这里主要演示管道形态。)
常见内置函数
| 函数 | 作用 | 例子 |
|---|---|---|
printf | 格式化 | {{printf "%.2f" .Price}} |
len | 长度 | {{len .Items}} |
index | 下标/键访问 | {{index .Items 0}} |
slice | 切片(新版本支持) | {{slice .Items 0 3}} |
and/or/not | 逻辑 | 见上 |
urlquery | 查询参数转义 | {{.Q | urlquery}} |
js / html 等 | 按上下文转义 | 较少手写 |
index详解
{{index .Scores 0}} <!-- slice[0] -->{{index .UserMap "u100"}} <!-- map["u100"] -->{{index .Matrix 1 2}} <!-- 多维:先 [1] 再 [2] -->当字段名是动态字符串、或键不是合法标识符时,index 很有用。
printf详解
{{printf "%s-%d" .Name .Age}}{{.Price | printf "¥%d"}}9. 综合示例:商品列表页
main.go 数据:
package mainimport ("html/template""os")type Product struct {Name stringPrice intTags []string}type Page struct {Title stringShopName stringVIP boolItems []Product}func main() {tmpl := template.Must(template.New("list").Parse(listHTML))data := Page{Title: "今日特价",ShopName: "七米小店",VIP: true,Items: []Product{{Name: "Go 书", Price: 88, Tags: []string{"编程", "热销"}},{Name: "键盘", Price: 299, Tags: []string{"外设"}},},}tmpl.Execute(os.Stdout, data)}const listHTML = `<!DOCTYPE html><html><head><meta charset="utf-8"><title>{{.Title}}</title></head><body> <h1>{{.Title}}</h1> <p>店铺:{{.ShopName}}</p> {{if .VIP}} <p>VIP 专属折扣已开启</p> {{else}} <p>开通 VIP 更优惠</p> {{end}} <p>共 {{len .Items}} 件商品</p> {{$shop := .ShopName}} <ul> {{range $i, $p := .Items}} <li> #{{$i}} [{{$shop}}] <strong>{{$p.Name}}</strong> {{printf "¥%d" $p.Price}} {{with $p.Tags}} 标签: {{range .}} <span>{{.}}</span> {{end}} {{end}} </li> {{else}} <li>暂无商品</li> {{end}} </ul> {{with index .Items 0}} <p>推荐:{{.Name}}</p> {{end}}</body></html>`这个例子一口气用到了:
- 输出、
if、len $shop保留外层range带索引with处理标签printf管道式格式化index取第一件商品
建议你改数据:把 Items 置空、把 VIP 改 false,观察分支变化。
10. 空值与安全输出意识
指针字段
type User struct {Name *string}若 Name == nil,{{.Name}} 可能出问题或为空。更稳妥是在 Go 侧先规范化数据,或模板里:
{{with .Name}}{{.}}{{else}}匿名{{end}}HTML 转义
html/template 会按插入点上下文转义。用户可控内容不要随便用 template.HTML 关闭转义(lesson08 会讲)。
缺失键
对 map,可设置:
tmpl.Option("missingkey=error")让访问不存在的 key 直接报错,便于调试
总结
相关文章
- 如何高效撰写意识形态工作汇报?一份详细的范文与提示词供你参考! 08-11
- AI图表,如何颠覆数据展示的未来 08-11
- 《逐出》第八关山顶介绍 08-11
- 如何将TXT数据转化为AI视觉的秘密武器 08-11
- AI仿写工具如何样助力企业在竞争中取得优势 08-11
- Zibrary中文官网入口 08-11