Go-知识 模板

Go-知识 模板

  • [1. 介绍](#1. 介绍)
  • [2. Text/template 包](#2. Text/template 包)
  • [3. Html/template 包](#3. Html/template 包)
  • [4. 模板语法](#4. 模板语法)
    • [4.1 模板标签](#4.1 模板标签)
    • [4.2 添加注释](#4.2 添加注释)
    • [4.3 访问变量](#4.3 访问变量)
    • [4.4 访问方法](#4.4 访问方法)
    • [4.5 模板变量](#4.5 模板变量)
    • [4.6 访问函数](#4.6 访问函数)
    • [4.7 数据渲染](#4.7 数据渲染)
    • [4.8 条件判断](#4.8 条件判断)
    • [4.9 循环遍历](#4.9 循环遍历)
    • [4.10 嵌入子模板](#4.10 嵌入子模板)
    • [4.11 局部变量](#4.11 局部变量)
    • [4.12 输出字符串](#4.12 输出字符串)
    • [4.13 预定义的全局函数](#4.13 预定义的全局函数)
    • [4.14 比较函数](#4.14 比较函数)

1. 介绍

fmt.Printf可以做到格式化输出,这对于简单的例子已经足够,但是有时候还需要更加复杂的输出格式,甚至需要将格式与代码分离开来。这个时候就可以使用模板(Template)。

2. Text/template 包

text/template包提供了处理文字模板与数据的功能,模板引擎。

所谓模板引擎,就是将模板和数据进行渲染的输出格式化后的字符串程序。

使用模板引擎分为三步:

  1. 创建模板对象
  2. 加载模板
  3. 执行渲染模板

比如如下例子:

go 复制代码
package gostudy

import (
	"os"
	"testing"
	"text/template"
)

func TestTe(t *testing.T) {

	templ := `
{{range.}}--------------------------------------
Name:  {{.Name}}
Age:   {{.Age}}
{{end}}
`
	tp := template.Must(template.New("templ").Parse(templ))
	type Person struct {
		Name string
		Age  int
	}
	persons := []Person{
		{"gw", 18},
		{"lx", 20},
		{"ly", 21},
	}
	if err := tp.Execute(os.Stdout, persons); err != nil {
		t.Log(err)
	}
}

执行结果如下

在代码中, templ 就是一段模板文字,然后使用程序中的数据,渲染模板,填充模板中的占位,最后得到完整的输出。

除了将模板文字在程序中写死,也可以将模板与程序分离,也就是格式和数据分离,使用不同的文件存储

首先创建一个文件用于存储模板文字,后缀可以自定义

然后在程序中直接加载模板文件

go 复制代码
func TestTeTxt(t *testing.T) {
	tp := template.Must(template.ParseFiles("./name_age.tpl"))
	type Person struct {
		Name string
		Age  int
	}
	persons := []Person{
		{"gw", 18},
		{"lx", 20},
		{"ly", 21},
	}
	if err := tp.Execute(os.Stdout, persons); err != nil {
		t.Log(err)
	}
}

执行结果与之前完全相同

如果要加载多个模板文件,有两种方式:枚举方式,正则方式 以及目录方式

枚举方式 tp := template.Must(template.ParseFiles("./name_age1.tpl", "./name_age2.tpl","./name_age3.tpl"))

正则方式 tp := template.Must(template.ParseGlob("./*.tpl"))

目录方式

go 复制代码
	files, err := filepath.Glob("./*.html.tmpl")
	if err != nil {
		log.Fatalf("Error while globbing files: %v", err)
	}
	tp := template.Must(template.ParseFS(os.DirFS("./)"), files...))

template.Must 主要是检测模板是否正确。

3. Html/template 包

text/template类似,html/template主要提供支持 HTML 模板的功能,使用方法差不多。

创建一个index.html.tmpl 文件

模板内容如下

txt 复制代码
<!doctype html>
  <head>
    <meta charset="UTF-8">
    <meta name="Author" content="">
    <meta name="Keywords" content="">
    <meta name="Description" content="">
    <title>Go</title>
  </head>
  <body>
    {{.}}
  </body>
</html>

然后创建一个web服务端

go 复制代码
func TestHt(t *testing.T) {
	tp := template.Must(template.ParseFiles("./index.html.tmpl"))

	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		tp.Execute(writer, "Hello")
	})
	http.ListenAndServe(":8080", nil)

}

访问

在多模板的时候,可以定义模板的名字,然后在执行的时候,指定模板渲染

比如

使用 {``{ define "index"}} 定义了模板的name

然后加载模板的时候,加载全部的模板,指定index1 执行

go 复制代码
func TestHt(t *testing.T) {
	files, err := filepath.Glob("./*.html.tmpl")
	if err != nil {
		log.Fatalf("Error while globbing files: %v", err)
	}
	tp := template.Must(template.ParseFS(os.DirFS("./"), files...))
	http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
		tp.ExecuteTemplate(writer, "index1", "Hello")
	})
	http.ListenAndServe(":8080", nil)
}

执行并访问

同时在模板文件之间可以进行嵌套

比如如下模板

然后修改index1.html.tmpl

重启web

4. 模板语法

4.1 模板标签

{``{}} 就是模板标签,中间是模板的语法内容。

4.2 添加注释

{``{/* 注释 */}}, 使用 {``{/**/}} 包含注释的内容。

tmpl 复制代码
    2. 注释 `{{/* 注释 */}}`: <br/>
    {{/* 这是一条注释 */}}
    <br/>

4.3 访问变量

{``{.}} 此标签输出当前对象值。

{``{.Name}} 表示输出对象中字段或方法名为 Name 的值。

需要注意,如果方法定义为 func (p Person)Name() string 那么,在渲染模板的时候,一定是值对象。

如果方法定义为 func (p *Person)Name() string 那么,在渲染模板时,一定是指针对象。

如果 Name 是匿名字段,那么还可以继续访问内部字段,比如 {``{.Name.First}}

如果存在一个方法Say,并且是 Name 的方法。

假设Say返回对象,那么可以继续访问{``{.Name.Say.Field}}

{``{.F1.F2.F3}},F 可以是方法也可以是结构体。(要小心空指针)

tmpl 复制代码
    1. 输出当前对象的值 `{{ . }}` : <br/>
    {{ . }}
    <br/>
        3. 变量: <br/>
      3.1 当前对象 `\{\{ . \}\}` : {{ . }} <br/>
          属性 NameStr : {{ .NameStr }} <br/>
      3.2 方法 `\{\{ .Name \}\}` : {{ .Name }} <br/>
      3.3 定义变量 `\{\{ $x := "test" \}\}` : {{ $x := "test" }} <br/>
      3.4 访问变量 `\{\{ $x \}\}` : {{ $x }} <br/>
      3.5 定义变量 n , 接收当前对象的值,然后传递给 ForName 函数,返回 对象并打印输出: <br/>
          `\{\{ $n := .NameStr \}\}`,`\{\{ .ForName $n \}\}` <br/>
          实际上等价于 `\{\{ .ForName \}\}` <br/>
          {{ $n := .NameStr }} <br/>
          {{ $n }} <br/>
          {{ .ForName $n }} <br/>
          {{ .ForName .NameStr }} <br/>

4.4 访问方法

{``{.Method param1 param2 param3}} 调用方法 Method,后面的 param是调用参数

4.5 模板变量

在模板中定义变量,变量名称用字母和数据组成,并加上 $ 前缀,采用简短赋值。

比如 {``{ $x := "OK" }}, {``{ $y := "yes"}}

访问定义的模板变量

{``{ $x }} 用于输出在模板中定义的名称为 x 的变量,当 定义的变量是个结构体的时候,可以连续访问

4.6 访问函数

  • 函数:在 Go 中,函数是独立的,必须显式地注册到模板中,以便在模板中使用。
  • 方法:方法是与特定类型(如结构体)关联的。当你在模板中使用结构体的实例时,模板引擎会自动识别该实例的方法。

在模板中要使用函数,必须先注册,不注册的话,是不能使用的

{``{ FuncName1 }} 调用标签名字为 FuncName1 的函数,等价于执行 FuncName1()

{``{ FuncName1 param1 param2 ..}} 调用带有参数的函数

{``{ FuncName1 . }} 等价于 FuncName1(this),这里的 this 取决于传递给模板渲染时的数据。

{``{ .|FuncName1 }}{``{ FuncName1 . }}

tmpl 复制代码
      3.6 访问函数 `\{\{ SayName .NameStr \}\}`: {{ SayName .NameStr }} <br/>
      3.7 访问函数 `\{\{ .|Say  \}\}` : {{ .|Say }} <br/>
          访问函数 `\{\{ Say . \}\}` : {{ Say . }} <br/>

4.7 数据渲染

在模板渲染的时候,如果想使用复杂的数据结构或者需要渲染很多数据,那么可以使用复杂struct 或者map进行传递。

如果使用map

go 复制代码
	data := map[string]interface{}{
		"NameStr": "xiaomei",
		"Age":     18,
		"Country": "China",
	}

模板

tmpl 复制代码
<h1>{{ SayHello .NameStr }}!</h1>
<p>Age: {{ .Age }}</p>
<p>Country: {{ .Country }}</p>

使用struct通常更具可读性和类型安全,而使用 map 则提供了更大的灵活性。

4.8 条件判断

{``{ if condition }} T1 {``{ end }} 结构为 {``{ if ... }} ... {``{ end }},类似go里面单个 if

{``{ if condition }} T1 {``{ else }} T2 {``{ end }}结构为{``{ if ... }} ... {``{ else }} ... {``{ end }},类似 go 里面的 if-else

{``{ if condition }} T1 {``{ else if con2}} T2 ... {``{ else }} Tn {``{ end }} 类似go 里面的多if分支

if 后面可以是一个条件表达式,条件可以是调用函数,方法等等,也可以是一个字符串变量或者布尔值变量。

当是字符串变量时,空字符串为 false,非空为true。

tmpl 复制代码
    4. 条件 <br/>
      Sex = {{ .Sex }}, Age = {{ .Age }} <br/>
      单个 if : {{ if eq .Sex "woman" }}
                 女
               {{ else }}
                 男
               {{ end }}
                <br/>
      多个 if :
      {{ if and  (eq .Sex "woman") (le .Age 18 ) }}
        少女
      {{ else if and (eq .Sex "man") (le .Age 18 ) }}
        少男
      {{ else }}
        其他
      {{ end }}

4.9 循环遍历

{``{ range $k,$v := .Var }} T {``{ end }} range ... end 结构内部如果要使用外部的变量,需要在外部变量的名字前加 $

{``{ range .var }} {``{ . }} {``{ end }} 将遍历值直接展示出来

{``{ range condition }} T {``{ else }} TT {``{ end }} 当没有可遍历的值的时候,执行 else 部分

tmpl 复制代码
5. 循环遍历 <br/>
      遍历数组直接输出<br/>
      {{ range .Msg }}
        {{ . }} ,
      {{ end }}
      <br/>
      遍历map输出<br/>
      {{ range .MsgMap }}
        {{ . }}
      {{ end }}
      <br/>
      遍历输出 k,v <br/>
      {{ range $k,$v := .MsgMap }}
        ( {{ $k }} , {{ $v }} ) <br/>
      {{ end }}
      <br/>
      定义外部变量 {{ $t := "say:" }} <br/>
      使用外部变量 <br/>
      {{ range $k,$v := .MsgMap }}
        {{ $t }} : {{ $k }} => {{ $v }} <br/>
      {{ end }}
      <br/>
      带有条件的循环遍历<br/>
      {{ range $k, $v := .MsgMap }}
        {{ if le $v 3 }}
          {{ $k }} => {{ $v }} <br/>
        {{ else }}
          ({{$k}},{{$v}})<br/>
        {{ end }}
      {{ end }}
      <br/>

输出

4.10 嵌入子模板

{``{ template "name"}} 嵌入名称为 "name" 的子模板。 使用前必须使用 {``{ define "name"}} ... {``{ end }} 进行定义

tmpl 复制代码
{{ define "div" }}
<div>
 <b> World </b>
</div>
{{ end }}
tmpl 复制代码
    6. 子模板 <br/>
      {{ template "div" }}

子模板可以嵌套多次,嵌套多个

4.11 局部变量

{``{ with ...}} T {``{ end }} 将值赋值给标签内部的 .

{``{ with ...}} T {``{ else }} TT {``{end}} 如果值为空,执行 else

tmpl 复制代码
7. 局部变量 <br/>
      {{ with .NameStr }}
        nameStr = {{ . }}<br/>
      {{ end }}
      <br/>
      带有 else 的 with <br/>
      {{ with "" }}
        不空
      {{ else }}
        空
      {{ end }}
      <br/>

4.12 输出字符串

{``{ "\"output\""}} 转义输出

` 可以使字符串原样输出

{``{ pintf "%q" "output"}} 函数调用输出 等价于 printf("%q", "output")

{``{ "output"|printf "%q"}} 另一种调用方式 printf("%q","output")

{``{ printf "%q" (print "out" "put")}} 多层调用 printf("%q", print("out","put"))

{``{ "put" | print "%s%s" "out" | printf "%q"}} 另一种写法printf("%q", print("%s%s", "out","put"))

{``{ "output" | prinf "%s" | printf "%q"}} 等价于 printf("%q", printf("%s", "output"))

{``{ with "output"}} {``{ printf "%q" .}} {``{ end }} 使用 .的with 写法

{``{ with $x := "output" | printf "%q"}} {``{ $x }} {``{ end }} 使用通道的with写法

{``{ with $x := "output"}} {``{ $x | printf "%q"}} {``{ end }} 另一种写法

tmpl 复制代码
8. 字符串<br/>
      {{ "\"output\"" }} <br/>
      {{ `"output"` }} <br/>
      {{ `{{ printf "%q" "output" }}` }} {{ printf "%q" "output" }}<br/>
      {{ with "output" }} {{ . | printf "%q" }} {{ end }} <br/>

4.13 预定义的全局函数

{``{ and x y}} 如果 x 为真,返回 y,否则返回 x

{``{ or x y }} 如果 x 为真,返回x ,否则返回 y

{``{ call func param1 param2 ...}} 调用函数,函数返回值限定为 1个或者2个(第二个必须是 error)

如果传递的参数与函数定义的不匹配,或者返回的 error 不为 nil ,停止执行

{``{html}} 转义文本中的 html 标签

{``{ index map 1 2 3}} 返回 index 后面的第一个参数的某个索引对应的元素值,其余参数作为索引值。必须是 map,数组,slice

{``{ js }} 返回用 javascript 的 escape 处理后的文本

{``{ len x }} 返回长度

{``{ not x}} 取反

{``{ print }} fmt.Sprint 的别名

{``{ printf }} fmt.Sprintf 的别名

{``{ println }} fmt.Sprintln的别名

{``{ urlquery }} 在URL查询中嵌入到形参中的文本转义,类似 urlencode

tmpl 复制代码
    9. 预定义<br/>
    			<p>and: {{ and true "Y" }}</p>
    			<p>or: {{ or false "Y" }}</p>
    			<p>len: {{ len .Msg }}</p>
    			<p>not: {{ not false }}</p>
    			<p>print: {{ print "Hello, " "World!" }}</p>
    			<p>printf: {{ printf "Hello, %s!" "World" }}</p>
    			<p>println: {{ println "Hello," "World!" }}</p>
    			<p>index: {{ index .MsgMap "two" }}</p>
    			<p>call: {{ call .SayN "xiaomei" }}</p>

4.14 比较函数

{``{ eq arg1 arg2}} :=> arg1 == arg2

{``{ ne arg1 arg2 }} :=> arg1 != arg2

{``{ lt arg1 arg2 }} :=> arg1 < arg2

{``{ le arg1 arg2 }} :=> arg1 <= arg2

{``{ gt arg1 arg2 }} :=> arg1 > arg2

{``{ ge arg1 arg2 }} :=> arg1 >= arg2

比较函数对任何零值返回 false ,非零值返回 true 。

比较函数每次只接受两个参数

{``{ eq arg1 arg2 arg3 arg4}} 等价于 arg1 == arg2 || arg1 == arg3 || arg1 == arg4

相关推荐
顾琬清14 分钟前
Linux系统Docker部署开源在线协作笔记Trilium Notes与远程访问详细教程
开发语言·后端·golang
小刀飘逸2 小时前
部署go项目到linux服务器(简易版)
后端·go
我是唐青枫2 小时前
如何用Go写一个benchmark 解析器及Web UI 数据可视化?
golang
东方窅瞳3 小时前
Bash语言的哈希表
开发语言·后端·golang
我是前端小学生4 小时前
Go 语言中的 Channel 全面解析
go
IT杨秀才5 小时前
Go语言单元测试指南
后端·单元测试·go
东方醴歌7 小时前
VMware安装飞牛私有云fnOS并挂载小雅Alist实现异地远程访问
开发语言·后端·golang
LuckyLay8 小时前
LeetCode算法题(Go语言实现)_39
算法·leetcode·golang
东方醴歌9 小时前
本地搭建直播录屏应用并实现使用浏览器远程控制直播间录屏详细教程
开发语言·后端·golang
ILHONG10 小时前
码云如何构建自己的golang内源包
开发语言·后端·golang