范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

gotemplate全面讲解

  什么是go - template
  你可以把它理解为Java的jsp,理解为js的ejs,vue的template,等等就是一个模版,所以就是需要了解一些模版的语法,以及渲染机制等,本文基本覆盖的很全面,模版其实核心是理解:1、基本语法,2、自定义func使用和内置func使用,3、变量的使用,4、模版复用等机制。
  如果你掌握以上我说的,那么开发一个模版工具,是很轻松的,比如orm通用代码,其他工具等。
  以下就是个demo: func TestTemplateString(t *testing.T) {     tmpl := "my name is {{.}}"     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, "anthony") } // my name is anthony
  所以需要模板渲染的部分都需要加入 {{}}   , 有些部分操作需要加入{{end}}   作为标识符等。简单语法学习{{.}}
  可以展示任何数据,各种类型的数据,可以理解为接收类型是 interface{}  func TestTemplateString(t *testing.T) {     tmpl := "my name is {{.}}"     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, []string{"hao", "dong"}) }  === RUN   TestTemplateString my name is [hao dong]--- PASS: TestTemplateString (0.00s) PASS{{.Field}}func TestTemplateStruct(t *testing.T) {     tmpl := `my name is "{{.Name}}"`     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, struct{ Name string }{Name: "anthony"}) }{{/* a comment */}}
  给go文件加入注释  func TestTemplateCommon(t *testing.T) {     tmpl := `{{/* a comment */}}`     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, struct{ Name string }{Name: "anthony"}) } // 什么也不输出{{-content-}}
  去除前后空格,超级方便好用  func TestTemplateTrim(t *testing.T) {     tmpl := `              {{- . -}}             `     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, "hello")  } //=== RUN   TestTemplateTrim //hello--- PASS: TestTemplateTrim (0.00s)
  如果不去会是这样子 func TestTemplateTrim(t *testing.T) {     tmpl := `              {{ . }}             `     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, "hello") } //=== RUN   TestTemplateTrim // //             hello             --- PASS: TestTemplateTrim (0.00s) //PASS条件语句{{ifcondition}}do{{else}}doelse{{end}}这个语意是如果true,则do,否则do-else,必须最后申明  {{end}}   , 跟我的ifelse   一模一样的
  doelse的条件为 : false、0、任意 nil 指针、接口值、数组、切片、字典和空字符串  ""  (长度为 0 的字符串)。func TestTemplateIf(t *testing.T) {     tmpl := `{{if .flag -}}              The flag=true              {{- else -}}              The flag=false              {{- end}} `     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, _map{         "flag": true,     })     _ = parse.Execute(os.Stdout, _map{         "flag": false,     }) }  === RUN   TestTemplateIf The flag=true The flag=false --- PASS: TestTemplateIf (0.00s) PASS循环语句{{range content}}T1{{end}}
  语意很简单,就是遍历内容  func TestRange(t *testing.T) {     tmpl := `{{range .Array}}              {{- . -}},              {{- end}} `     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, struct {         Array []string     }{Array: []string{"a", "b", "c"}}) } //=== RUN   TestRange //a,b,c, //--- PASS: TestRange (0.00s){{range content}}T1{{else}}T0{{end}}
  如果数组为空,输出else的东西  func TestRangeEmpty(t *testing.T) {     tmpl := `{{range .Array}}              {{- . -}},              {{else -}}               array null              {{- end}} `     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, struct {         Array []string     }{Array: []string{}}) } //=== RUN   TestRangeEmpty //array null //--- PASS: TestRangeEmpty (0.00s){{range $index,$value:=pipeline}}T1{{end}}{{range $key,$value :=pipeline }}T1 {{end}}   也适用,用于遍历
  关于  $key  ,这个属于变量操作,后面会讲到func TestRange(t *testing.T) {     tmpl := `{{range $key, $value:=.Array}}              {{- $key}}:{{$value}},              {{- end}} `     parse, _ := template.New("demo").Parse(tmpl)     _ = parse.Execute(os.Stdout, struct {         Array map[string]string     }{Array: map[string]string{"a": "1", "b": "2", "c": "3"}}) } //=== RUN   TestRange //a:1,b:2,c:3, //--- PASS: TestRange (0.00s){{ range pipeline }} T1 {{ end }}  // 这个 else 比较有意思,如果 pipeline 的长度为 0 则输出 else 中的内容 {{ range pipeline }} T1 {{ else }} T0 {{ end }}  // 获取容器的下标 {{ range $index, $value := pipeline }} T1 {{ end }}FuncMap(很重要)1、自定义函数
  type FuncMapmap[string]interface{}
  它有一个比较好的功能就是,自定义函数  func TestFuncMap(t *testing.T) {     tem, _ := template.New("").Funcs(map[string]interface{}{         "ReplaceAll": func(src string, old, new string) string {             return strings.ReplaceAll(src, old, new)         },     }).Parse(`func replace: {{ReplaceAll .content "a" "A"}}`)     tem.Execute(os.Stdout, map[string]interface{}{         "content": "aBC",     }) }  === RUN   TestFuncMap func replace: ABC--- PASS: TestFuncMap (0.00s) PASS
  其中,不能写 {{ReplaceAll.content a A}}   ,因为go不识别 a 是一个字符串,所以必须加引号
  如果理解了这个,其实对于一些内置函数会理解很多,其中对于函数的要求是: // 写法错误:不允许有两个参数返回值,如果是两个返回值,第二个必须是error "ReplaceAll": func(src string, old, new string) (string, string) {   return strings.ReplaceAll(src, old, new), "111" },  // 写法正确: 如果两个返回类型,第二个必须是error,顺序不能颠倒 "ReplaceAll": func(src string, old, new string) (string, error) {   return strings.ReplaceAll(src, old, new), nil },  // 写法正确: 如果是一个返回类型,直接返回就行了 "ReplaceAll": func(src string, old, new string) string {   return strings.ReplaceAll(src, old, new) },  // 写法正确:参数可以不传递,但是必须有返回值的(其实可以理解,没有返回值,你渲染啥) tem, _ := template.New("").Funcs(map[string]interface{}{   "Echo": func() string {     return "hello world"   }, }).Parse(`func echo : {{Echo}}`)  // 写法错误:不允许没有返回参数,直接panic "ReplaceAll": func(src string, old, new string)  {    strings.ReplaceAll(src, old, new) },
  其实理解了funcmap,你就理解了内置函数如何玩的,接下来就会说的,不用死记硬背。  2、内置函数
  内置函数本质上也是 FuncMap,所以如果掌握了如何使用FuncMap,其实就会这个了。  eqfunc TestEQ(t *testing.T) {     parse, _ := template.New("").Parse(`{{eq .content1 .content2}}`)     parse.Execute(os.Stdout, _map{         "content1": "a",         "content2": "b",     }) }  === RUN   TestEQ false--- PASS: TestEQ (0.00s) PASScallfunc TestCall(t *testing.T) {     parse, _ := template.New("").Parse(`{{call .fun .param}} `)     parse.Execute(os.Stdout, _map{         "fun":   func(str string) string { return strings.ToUpper(str) },         "param": "abc",     }) }  === RUN   TestCall ABC --- PASS: TestCall (0.00s) PASS
  其实就是这么简单,对于call函数来说,它必须要求返回参数格式是1或2个,其中如果是两个则必须一个是error func call(fn reflect.Value, args ...reflect.Value) (reflect.Value, error)  func safeCall(fun reflect.Value, args []reflect.Value) (val reflect.Value, err error) {     defer func() {         if r := recover(); r != nil {             if e, ok := r.(error); ok {                 err = e             } else {                 err = fmt.Errorf("%v", r)             }         }     }()     ret := fun.Call(args)   // 结果如果两个,则必须有一个是error     if len(ret) == 2 && !ret[1].IsNil() {         return ret[0], ret[1].Interface().(error)     }     return ret[0], nil }变量
  变量通常适用于定义了某个值,申明很简单,和写php一样,变量前面需要加入一个  $   ,注意的是需要渲染的部分全部需要用{{}}   包起来func TestVariable(t *testing.T) {     tmpl, err := template.New("test").Parse(`{{$a := "anthony"}} hello {{$a}}`)     if err != nil {         panic(err)     }     err = tmpl.Execute(os.Stdout, nil)     if err != nil {         panic(err)     } }
  其实跟我的go预发基本一致。 模版嵌套
  自定义内嵌的模板  {{define "template_name"}}template_content {{end}}  ,其中就是一种模版复用的机制。 那么如何模版引用呢{{template"template_name""args"}}   ,记得传入两个参数就行,一个模版的名称(记住申明模版名称需要加上""  ),一个是你的模版需要的参数。func TestTemplateInternal(t *testing.T) {     parse, _ := template.New("").Parse(`         {{define "print"}}my name is {{.}} {{end}}         {{- template "print" .name}}     `)     parse.Execute(os.Stdout, _map{         "name": "hao dong",     }) }  === RUN   TestTemplateInternal         my name is hao dong      --- PASS: TestTemplateInternal (0.00s) PASSformat 工具
  我们知道,go是有个fmt插件,可以帮助format 文件,所以在这里go 也提供了format  func TestFormat(t *testing.T) {     parse, _ := template.New("").Parse(`         package main         import  "fmt"           func main(){             fmt.Println("{{.}}")         }      `)     parse.Execute(os.Stdout, _map{"data":"1111"}) }  // 结果:是不是很乱,但是别慌 === RUN   TestFormat          package main         import  "fmt"           func main(){             fmt.Println("map[data:1111]")         }      --- PASS: TestFormat (0.00s) PASS
  如何使用format呢 ? func TestFormat(t *testing.T) {     parse, _ := template.New("").Parse(`         package main         import  "fmt"           func main(){             fmt.Println("{{.}}")         }      `)      buffer := &bytes.Buffer{}     parse.Execute(buffer, _map{"data":"1111"})     source, _ := format.Source(buffer.Bytes())     fmt.Printf("%s",source) }  === RUN   TestFormat package main  import "fmt"  func main() {     fmt.Println("map[data:1111]") } --- PASS: TestFormat (0.00s) PASS
  是不是变得很整齐。 总结
  go 原生的提供了模版机制,对于开发者相当友好,尽管第三方包有很多模版工具,但是原生是最好的,因为不需要引入依赖。
  模版通常用于生成一些复用的代码,比如 protobuf文件生成, 比如orm框架的model,dao等,都是需要改进的 参考
  https://juejin.im/post/5c403b98f265da612d1984c9
  https://juejin.im/post/5eb232026fb9a043867d50ae

邓伦生日闪现八城地标,品牌这波芯光祝福也太秀了每一剪光影彰显无与伦比的魅力踏实沉淀自我积蓄演员的能量,专注解读作品赋予角色的层次,他的品格与魅力令人伦陷。祝邓伦生日快乐,时光不会辜负静心努力的人,请继续执着勇敢地前行10月21三十而励,细节处处不同微软为李现送上地标生日广告祝福最好的李,就是现在在演员职业里,怀炽热初心真诚对待表演,以角色体会多重人生在日常生活中,跃进人海深入生活感受万物,以自在拥抱广阔世界。微软x李现生日x地标马克户外广告灯光秀与光影交战火再燃!户外地标广告打响街舞终极之战这!就是街舞4全球精英争霸赛倒计时10月25日,多地上演这街4灯光大秀,潮燃名场面令人震撼!地标马克点亮旗下两城地标灯光秀为巅峰之夜这!就是街舞第四季总决赛闪耀加码!这!就是街舞x纪念二万五千里的奇迹地标马克户外广告全国9城地标集体点亮今天,纪念红军长征伟大胜利红军不怕远征难,万水千山只等闲。长征胜利85周年x地标马克户外公益广告灯光秀85年前的今天,有一支英雄的部队,纵横二万五千里,在中国地图上谱写了一部气吞山幽会王维我穿越到唐宋走近唐宋的文人骚客与先哲大师来一场心灵约会,我觉王维大概是最能看透人生意义的,并善于享受生活珍惜人生当下的人。王维晚年退隐终南山参禅悟理,学庄信道,精通诗书画音乐。诗名盛于开元天宝心安处天涯何处不故乡晓风星月,反思过往深圳是实现梦想的天堂,在这里,年青人至少不用担心七大姑八大姨的催婚,努力往前冲就好了,在这里没有任何人嘲笑你,思想奇特,异想天开,因为没有人怀疑一个努力的人突然成晓风残月悟道人生跳出三界外晓风残月悟道人生跳出三界外,人生时时要悟道,跳出三界其实是道家术语,但依然有现实中的指导意义,现实中人要跳出束缚你,压抑你激情的圈子,现实中就象鸟寻觅更适合容身与觅食的圈子,当一个鹏城蔚蓝的天缱绻了五月的时光行走在铺满阳光的小径,轻嗅风中花香的美好,心思是否会如露珠般晶莹剔透呢?最好的时光,应开出最好的花吧。时光,留不住昨天缘分,停不在初见。漫漫历史长河中,我们都是岁月中的微不足道的小晓风残月子夜扰思醉酒的夜晚周未出差广州,夜色中的羊城让我迷醉,今天下午头条上一震憾心灵的消息让我半天缓不过神,袁隆平院士袁老于今日2点7分走了。再加上前两天的那个拥有1000亿财富帝国的左辉也走了。网上一片精神的世外桃园晓风夜月,夜读心灵深圳住久了,总能避开很多是非,那些形式上的礼尚往来的虚情假意,和无效社交觥筹交错,简直是醉生梦死蹉跎岁月,但在深圳完全可享受自由,享受寂寞,享受孤独,是深圳一种特激情在深圳湾的日出里沉醉每日面对深圳湾日出,就象给心灵充电,蓄存光阴里阳光与快乐。随着环境与经济状况的焕然一新,会看淡了很多人很多事,却再也不想随便捅破,包括讨厌的人和事,再也没必要去交往,不值得去认真更
你能忍受的最长手机充电时间是多长?是两个小时因电池板暴费了充电续度漫只能等待。我忍受最长手机充电时间是。腄觉自然醒了。四五个小时是正常。现代化建设中国特色社会主义国家高质量。高科技产品华为手机非常安全保质保量。靓妹住友化学研发出智能手机屏幕内嵌入式透明5G天线技术CINNOResearch产业资讯,住友化学研发出智能手机显示屏内嵌入式透明5G天线技术。并将制成透明天线的薄膜作为显示屏组件进行供货。该技术通过接收从手机正面到达的无线电波,从而威联通TS551搭配东芝NAS硬盘MN系列搭建家庭媒体中心体验分享创作声明原创分享,拒绝搬运转载前言大家好,我是Karl,一个电脑数码爱好者,喜欢打游戏按快门看小姐姐,喜欢看文档写文档和分享。作为一个数码爱好者,我在役的有一个台式机两个笔记本一个小米平板5pro的简单上手体验我前几天就去实体店体验过小米平板5pro,趁周末有空就写一篇个人体验。因为不是专业人士,写得不好,只给想买的网友们做个参考。第一感觉边框稍宽,手感质感还不错。我上手体验了一下系统还亚马逊封号潮后清库存广告扎堆朋友圈,大卖低价清仓图片来源图虫创意编者按今年4月开始,亚马逊掀起一场旷日持久的封号潮,截至目前为止,已有超5万卖家受影响。在外界普遍看好跨境出口电商,大量线下实体品牌外贸工厂淘系品牌涌入的同时,曾经想给男朋友买一个笔记本电脑,我也不是很懂,大家有什么推荐嘛?选择笔记本电脑首先要确定使用需求和预算,有需求和预算才好推荐哦。一选购笔记本电脑常见问题1,品牌选择在品牌售后方面,联想惠普戴尔华硕等老牌电脑品牌会更具优势。神舟主打性价比,在售后外星生命不一定是人,而可能是高等智慧生物,你怎么看?外星生命不一定是人,这是肯定正确的,人只是地球上才有的生物类型,因为人是根据地球大气环境主要构成成分引力场等环境因素形成的,人适合地球上生存。外星生命可能是高等智慧生物,也可能是低投诉数据告诉你,大数据杀熟有哪些套路?来源读特人工智能正像电力一般赋能各个产业,深刻地改变人类社会。中国正处于全球人工智能发展第三次浪潮的时代潮头,算法周刊将聚焦人工智能上海高地和中国新基建,并持续关注全球AI最前沿。他高中毕业,从快递员变成老板,拿5亿开公司,却因为5毛钱被痛骂2016年4月,一名顺丰快递员在北京富贵园和往常一样骑着三轮车来来回回送快递,结果不小心和小区内一辆现代轿车剐上了。车主气愤地从车上冲下来,不由分说对着顺丰小哥又骂又打,前前后后扇马斯克狗狗币是在支付方面最强的加密货币8月14日,特斯拉CEO埃隆马斯克再次强调,狗狗币以比其他加密货币更好的方式实现了支付手段的属性。他在推特中对同为亿万富翁的MarkCuban的观点表示赞同。Cuban最近在接受C定位SUV,但酷似MPV,空间还超大,10。46万起售,AIONY如何?全民说车汽车内容创作季说到广汽埃安,作为广汽新能源旗下的独立品牌,旗下的产品定位也是主打家用车系列。埃安自从独立出来之后,它的势头也是一直不错,在销量榜单上也常能见到其产品的身影,