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

相关推荐
豆约翰8 小时前
golang点类圆类求pi值
开发语言·后端·golang
007php00710 小时前
服务器systemctl命令使用与go项目zero框架中实战
java·运维·服务器·网络·golang·php·ai编程
司马相楠12 小时前
嵌入式开发 的软件开发技能
开发语言·后端·golang
ac-er888812 小时前
Go work stealing 机制
java·数据库·golang
Ai 编码助手15 小时前
程序员如何培养技术领导力?
java·c语言·开发语言·golang·php
迷茫运维路15 小时前
golang标准库archive/tar实现打包压缩及解压
运维·开发语言·golang
007php00719 小时前
分析服务器 systemctl 启动gozero项目报错的解决方案
linux·运维·服务器·python·docker·golang·php
ThisIsClark21 小时前
【gopher的java学习笔记】依赖管理方式对比(go mod & maven)
java·golang·maven
Pandaconda21 小时前
【Golang 面试题】每日 3 题(十三)
开发语言·笔记·后端·面试·职场和发展·golang·go
ac-er88881 天前
Go recover的执行时机
开发语言·后端·golang