template之前也使用过,但都是一些最简单的字符串替换,但是从来没有使用过数组的循环遍历.

官方文档在这: https://golang.org/pkg/text/template/ 。 看的云里雾里的

之前做prometheus监控告警的时候为了适配各种类型的告警,把告警表达式模板抽出来了。

avg by(instance,prometheus_replica) (rate(node_cpu_seconds_total{mode = 'system', instance =~ '^{{.host}}.*'}[5m])) * 100

代码简单, expression 是PromQL表达式模板,使用 { { }} 作为定界符,queryMap的key是具体要替换的字符串,比如host,queryMap的value是具体的值,比如10.10.13.2。

func GetQueryPromQlExpr(name, expression string, queryMap map[string]interface{}) string {
	tpl := template.Must(template.New(name+"-expr").Delims("{{", "}}").Parse(expression))
	var buf bytes.Buffer
	err := tpl.Execute(&buf, queryMap)
	if err != nil {
		klog.Errorf("parse query:%s expression err:%s", name, err.Error())
		return ""
	return buf.String()

现在有个需求是给了我一个文件模板,模板里面的内容是动态的,尤其是模板里面还会涉及到数组的使用。

理想效果是这样的:

[masters]
master1.okd.local  10.10.11.1
master2.okd.local  10.10.11.2
master3.okd.local  10.10.11.3
[nodes]
node1.okd.local  10.10.12.1
node2.okd.local  10.10.12.2
node3.okd.local  10.10.12.3

但是前端给到我的是一个master ip的数组,[masters]模块里面的内容具体有多少行,取决于前端传入的master ip数组的大小。

当前给我的数组长度为3,那么就会有3行,同理如果数组长度为10,那么就会生成10行记录。

master后面的数字相当于是数组的索引(从1开始的),在每一行末尾还有一个ip地址。

定义结构体

type Manifest struct {
	ClusterDomain string
	MasterIps     []string
    NodeIps       []string

结构体里面的字段首字母要大写,否则一会儿运行模板的时候无法解析到。 

定义字符串模板

ClusterDomain是公共的,要在range里面使用,需要使用$.Var

参考:https://studygolang.com/articles/3071

var manifestTpl = `
[masters]
{{range $index, $value := .MasterIps}}
   master{{$index}}.{{$.ClusterDomain}} {{$value}}
{{end}}
[nodes]
{{range $index, $value := .NodeIps}} 
   master{{$index}}.{{$.ClusterDomain}} {{$value}}
{{end}}

循环模板,以及在循环内使用外部变量

func TestTmpl(t *testing.T) {
	manifest := Manifest{
		ClusterDomain: "okd.local",
		MasterIps:     []string{"10.10.13.2", "10.10.13.3"},
		NodeIps:       []string{"10.10.14.2", "10.10.14.3"},
	manifestTpl, err := template.New("manifest").Parse(manifestTpl)
	assert.Equal(t, nil, err)
	var buf bytes.Buffer
	assert.Equal(t, nil, manifestTpl.Execute(&buf, manifest))
	fmt.Println(buf.String())

目前这个代码执行出来的结果是下标从0开始。

下标从1开始

如果要让下标从0开始,可以自定义一个inc函数。

 funcMap := template.FuncMap{
        // The name "inc" is what the function will be called in the template text.
        "inc": func(i int) int {
            return i + 1

现在只要模板里面的index都调用inc参数即可实现在原有index基础上加1的效果。

var manifestTpl = `
[masters]
{{range $index, $value := .MasterIps}}
   master{{inc $index}}.{{$.ClusterDomain}} {{$value}}
{{end}}
[nodes]
{{range $index, $value := .NodeIps}} 
   master{{inc $index}}.{{$.ClusterDomain}} {{$value}}
{{end}}
func TestTmpl(t *testing.T) {
	manifest := Manifest{
		ClusterDomain: "okd.local",
		MasterIps:     []string{"10.10.13.2", "10.10.13.3"},
		NodeIps:       []string{"10.10.14.2", "10.10.14.3"},
	funcMap := template.FuncMap{
		// The name "inc" is what the function will be called in the template text.
		"inc": func(i int) int {
			return i + 1
	manifestTpl, err := template.New("manifest").Funcs(funcMap).Parse(manifestTpl)
	assert.Equal(t, nil, err)
	var buf bytes.Buffer
	assert.Equal(t, nil, manifestTpl.Execute(&buf, manifest))
	fmt.Println(buf.String())
                    template之前也使用过,但都是一些最简单的字符串替换,但是从来没有使用过数组的循环遍历.官方文档在这:https://golang.org/pkg/text/template/。 看的云里雾里的之前做prometheus监控告警的时候为了适配各种类型的告警,把告警表达式模板抽出来了。avg by(instance,prometheus_replica) (rate(node_cpu_seconds_total{mode = 'system', instance =~ '^{{.h..
				
前言:最近做的tasks基本上都是与golangtemplate有关,今天有时间,对go的template的基本也是常用的语法规则做一个小小的总结。把自己踩到的坑列出来 模板:何为template呢?golang里面的template不要认为和go的语法有什么关系,如果你那样觉得,那你就是too young too simple;template与go的语法其实一点关系也没有,甚至是完全不同的
go get github.com/pravj/cqueue 一个循环缓冲区结构 // CQueue represents a circular buffer data structure type CQueue struct { // size limit of the buffer size int // occupied size of the buffer Length int // list containing all the buffer elements Queue * list. List // element at the front-side of the buffer Head * list. Element // element at the back- golang(中文名:go语言)是谷歌2009发布的第二款开源编程语言。Go语言专门针对多处理器系统应用程序的编程进行了优化,使用Go编译的程序可以媲美C或C++代码的速度,而且更加安全、支持并行进程。。如果你想知道得更多,请移步至官网golang官网 在 Go 中函数的调用是值拷贝 copy value,而且在 for 循环中 v 的变量始终是一个变量。如果 v 是 pointer,print 这个 method 接收的是指针的拷贝,for 循环体中每次迭代 v 的 pointer value 都是不同的,所以输出不同。 在 Go 常见的错误一文中 http://devs.cloudi
文章目录1. 使用 map 的简单示例2. 循环2.1 `{{range $i, $e := pipeline }}2.2 {{range .pipeline}}引用外部变量 1. 使用 map 的简单示例 package main import ( "fmt" "text/template" "bytes" func main() { tplStr := `my name is ...
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <title>Go Web</title> </head> {{ range . }} <li>{{ . }}</li> {{ else }}
一:首先贴代码(你们大概看看就行,在看看后面的数据 你们就能理解 结构体嵌套的案例) 如果是PHP就方便很多,直接数组嵌套数组就行,也就是二维数组。 package model import ( type Find struct { Article []Article SelectArticle []SelectArticle RecoArticle []SelectArticle SelectLabel []SelectLabel IndexAbout SiteInfo IndexContact SiteInfo
go template 循环使用 外部变量 range…end结构内部如要使用外部变量,比如.Var,需要这样写:$.Var (即:在外部变量名称前加符号“”即可,单独的“”即可,单独的“”即可,单独的“”意义等同于global) npm i art-template 2.引入模板 <script src="./node_modules/art-template/lib/template-web.js"></script> 注意:要注意引入顺序 3.定义模板 定义一个 type="text/html"的 script标签 ,使用 each循环结构 并且...
这样,slice 就包含了数组中的前三个元素 {1, 2, 3}。需要注意的是,切片表达式中的 low 和 high 可以省略,如果省略 low,则默认从数组或切片的第一个元素开始;如果省略 high,则默认取到最后一个元素。 ```go slice1 := arr[:3] // 等价于 arr[0:3] slice2 := arr[2:] // 从第三个元素开始取到最后一个元素 slice3 := arr[:] // 包含整个数组的所有元素 除了使用切片表达式外,还可以使用数组和切片的内置方法来实现类似的功能。例如,可以使用数组的切片方法来获取数组中的一段连续元素: ```go arr := [5]int{1, 2, 3, 4, 5} slice := arr[0:3] 也可以使用切片的切片方法来获取切片中的一段连续元素: ```go slice1 := []int{1, 2, 3, 4, 5} slice2 := slice1[0:3]