一聚教程网:一个值得你收藏的教程网站

最新下载

热门教程

Go语言模板语法举例详细说明

时间:2026-08-11 11:35:50 编辑:袖梨 来源:一聚教程网

Go语言模板语法举例详细说明并不只看表面做法,关键还要理解相关条件、限制和后续影响。

引言

目标:吃透 {{ }} 里的动作(action):输出、变量、条件、循环、with、管道与内置函数。这是后面嵌套/继承/Gin 的语法基础。

Go语言模板语法举例详解

1. 模板语法总览

Go 模板里,普通文本原样输出;逻辑都写在 action 中:

{{ ... }}

常见类别:

类别例子作用
输出{{.Name}}打印值
注释{{/* ... */}}不输出
变量{{$x := .}}绑定到 $x
条件{{if}}...{{end}}分支
循环{{range}}...{{end}}遍历
改上下文{{with}}...{{end}}临时切换 .
管道{{. | printf "%s"}}函数链式处理
模板调用{{template "x" .}}嵌套(下节细讲)

2. 点(dot).:当前上下文

. 是模板里最重要的概念

  1. Execute(w, data) 时,根上下文 . = data
  2. 进入 range / with 后,. 可能变成「当前元素」
  3. 离开 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 主体):

  1. false
  2. 数字 0
  3. 空字符串 ""
  4. nil
  5. 空的 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 有两个作用:

  1. 判断值是否为真
  2. 若为真,在块内把 . 换成这个值
{{with .Profile}}  <p>城市:{{.City}}</p>  <p>签名:{{.Bio}}</p>{{else}}  <p>用户未填写资料</p>{{end}}

等价心智模型:

如果 Profile 有值:  进入块,且 . = Profile否则:  走 else

with+ 变量

{{with $p := .Profile}}  {{$p.City}}{{end}}

ifvswith

ifwith
是否切换 .
适合纯条件判断深入嵌套结构体字段

很多人写 {{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>`

这个例子一口气用到了:

  1. 输出、iflen
  2. $shop 保留外层
  3. range 带索引
  4. with 处理标签
  5. printf 管道式格式化
  6. index 取第一件商品

建议你改数据:把 Items 置空、把 VIPfalse,观察分支变化。

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 直接报错,便于调试

总结

热门栏目