gotemplate全面讲解
什么是gotemplate
你可以把它理解为Java的jsp,理解为js的ejs,vue的template,等等就是一个模版,所以就是需要了解一些模版的语法,以及渲染机制等,本文基本覆盖的很全面,模版其实核心是理解:1、基本语法,2、自定义func使用和内置func使用,3、变量的使用,4、模版复用等机制。
如果你掌握以上我说的,那么开发一个模版工具,是很轻松的,比如orm通用代码,其他工具等。
以下就是个demo:funcTestTemplateString(ttesting。T){tmpl:mynameis{{。}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,anthony)}mynameisanthony
所以需要模板渲染的部分都需要加入{{}},有些部分操作需要加入{{end}}作为标识符等。简单语法学习{{。}}
可以展示任何数据,各种类型的数据,可以理解为接收类型是interface{}funcTestTemplateString(ttesting。T){tmpl:mynameis{{。}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,〔〕string{hao,dong})}RUNTestTemplateStringmynameis〔haodong〕PASS:TestTemplateString(0。00s)PASS{{。Field}}funcTestTemplateStruct(ttesting。T){tmpl:mynameis{{。Name}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,struct{Namestring}{Name:anthony})}{{acomment}}
给go文件加入注释funcTestTemplateCommon(ttesting。T){tmpl:{{acomment}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,struct{Namestring}{Name:anthony})}什么也不输出{{content}}
去除前后空格,超级方便好用funcTestTemplateTrim(ttesting。T){tmpl:{{。}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,hello)}RUNTestTemplateTrimhelloPASS:TestTemplateTrim(0。00s)
如果不去会是这样子funcTestTemplateTrim(ttesting。T){tmpl:{{。}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,hello)}RUNTestTemplateTrimhelloPASS:TestTemplateTrim(0。00s)PASS条件语句{{ifcondition}}do{{else}}doelse{{end}}这个语意是如果true,则do,否则doelse,必须最后申明{{end}},跟我的ifelse一模一样的
doelse的条件为:false、0、任意nil指针、接口值、数组、切片、字典和空字符串(长度为0的字符串)。funcTestTemplateIf(ttesting。T){tmpl:{{if。flag}}Theflagtrue{{else}}Theflagfalse{{end}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,map{flag:true,})parse。Execute(os。Stdout,map{flag:false,})}RUNTestTemplateIfTheflagtrueTheflagfalsePASS:TestTemplateIf(0。00s)PASS循环语句{{rangecontent}}T1{{end}}
语意很简单,就是遍历内容funcTestRange(ttesting。T){tmpl:{{range。Array}}{{。}},{{end}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,struct{Array〔〕string}{Array:〔〕string{a,b,c}})}RUNTestRangea,b,c,PASS:TestRange(0。00s){{rangecontent}}T1{{else}}T0{{end}}
如果数组为空,输出else的东西funcTestRangeEmpty(ttesting。T){tmpl:{{range。Array}}{{。}},{{else}}arraynull{{end}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,struct{Array〔〕string}{Array:〔〕string{}})}RUNTestRangeEmptyarraynullPASS:TestRangeEmpty(0。00s){{rangeindex,value:pipeline}}T1{{end}}{{rangekey,value:pipeline}}T1{{end}}也适用,用于遍历
关于key,这个属于变量操作,后面会讲到funcTestRange(ttesting。T){tmpl:{{rangekey,value:。Array}}{{key}}:{{value}},{{end}}parse,:template。New(demo)。Parse(tmpl)parse。Execute(os。Stdout,struct{Arraymap〔string〕string}{Array:map〔string〕string{a:1,b:2,c:3}})}RUNTestRangea:1,b:2,c:3,PASS:TestRange(0。00s){{rangepipeline}}T1{{end}}这个else比较有意思,如果pipeline的长度为0则输出else中的内容{{rangepipeline}}T1{{else}}T0{{end}}获取容器的下标{{rangeindex,value:pipeline}}T1{{end}}FuncMap(很重要)1、自定义函数
typeFuncMapmap〔string〕interface{}
它有一个比较好的功能就是,自定义函数funcTestFuncMap(ttesting。T){tem,:template。New()。Funcs(map〔string〕interface{}{ReplaceAll:func(srcstring,old,newstring)string{returnstrings。ReplaceAll(src,old,new)},})。Parse(funcreplace:{{ReplaceAll。contentaA}})tem。Execute(os。Stdout,map〔string〕interface{}{content:aBC,})}RUNTestFuncMapfuncreplace:ABCPASS:TestFuncMap(0。00s)PASS
其中,不能写{{ReplaceAll。contentaA}},因为go不识别a是一个字符串,所以必须加引号
如果理解了这个,其实对于一些内置函数会理解很多,其中对于函数的要求是:写法错误:不允许有两个参数返回值,如果是两个返回值,第二个必须是errorReplaceAll:func(srcstring,old,newstring)(string,string){returnstrings。ReplaceAll(src,old,new),111},写法正确:如果两个返回类型,第二个必须是error,顺序不能颠倒ReplaceAll:func(srcstring,old,newstring)(string,error){returnstrings。ReplaceAll(src,old,new),nil},写法正确:如果是一个返回类型,直接返回就行了ReplaceAll:func(srcstring,old,newstring)string{returnstrings。ReplaceAll(src,old,new)},写法正确:参数可以不传递,但是必须有返回值的(其实可以理解,没有返回值,你渲染啥)tem,:template。New()。Funcs(map〔string〕interface{}{Echo:func()string{returnhelloworld},})。Parse(funcecho:{{Echo}})写法错误:不允许没有返回参数,直接panicReplaceAll:func(srcstring,old,newstring){strings。ReplaceAll(src,old,new)},
其实理解了funcmap,你就理解了内置函数如何玩的,接下来就会说的,不用死记硬背。2、内置函数
内置函数本质上也是FuncMap,所以如果掌握了如何使用FuncMap,其实就会这个了。eqfuncTestEQ(ttesting。T){parse,:template。New()。Parse({{eq。content1。content2}})parse。Execute(os。Stdout,map{content1:a,content2:b,})}RUNTestEQfalsePASS:TestEQ(0。00s)PASScallfuncTestCall(ttesting。T){parse,:template。New()。Parse({{call。fun。param}})parse。Execute(os。Stdout,map{fun:func(strstring)string{returnstrings。ToUpper(str)},param:abc,})}RUNTestCallABCPASS:TestCall(0。00s)PASS
其实就是这么简单,对于call函数来说,它必须要求返回参数格式是1或2个,其中如果是两个则必须一个是errorfunccall(fnreflect。Value,args。。。reflect。Value)(reflect。Value,error)funcsafeCall(funreflect。Value,args〔〕reflect。Value)(valreflect。Value,errerror){deferfunc(){ifr:recover();r!nil{ife,ok:r。(error);ok{erre}else{errfmt。Errorf(v,r)}}}()ret:fun。Call(args)结果如果两个,则必须有一个是erroriflen(ret)2!ret〔1〕。IsNil(){returnret〔0〕,ret〔1〕。Interface()。(error)}returnret〔0〕,nil}变量
变量通常适用于定义了某个值,申明很简单,和写php一样,变量前面需要加入一个,注意的是需要渲染的部分全部需要用{{}}包起来funcTestVariable(ttesting。T){tmpl,err:template。New(test)。Parse({{a:anthony}}hello{{a}})iferr!nil{panic(err)}errtmpl。Execute(os。Stdout,nil)iferr!nil{panic(err)}}
其实跟我的go预发基本一致。模版嵌套
自定义内嵌的模板{{definetemplatename}}templatecontent{{end}},其中就是一种模版复用的机制。那么如何模版引用呢{{templatetemplatenameargs}},记得传入两个参数就行,一个模版的名称(记住申明模版名称需要加上),一个是你的模版需要的参数。funcTestTemplateInternal(ttesting。T){parse,:template。New()。Parse({{defineprint}}mynameis{{。}}{{end}}{{templateprint。name}})parse。Execute(os。Stdout,map{name:haodong,})}RUNTestTemplateInternalmynameishaodongPASS:TestTemplateInternal(0。00s)PASSformat工具
我们知道,go是有个fmt插件,可以帮助format文件,所以在这里go也提供了formatfuncTestFormat(ttesting。T){parse,:template。New()。Parse(packagemainimportfmtfuncmain(){fmt。Println({{。}})})parse。Execute(os。Stdout,map{data:1111})}结果:是不是很乱,但是别慌RUNTestFormatpackagemainimportfmtfuncmain(){fmt。Println(map〔data:1111〕)}PASS:TestFormat(0。00s)PASS
如何使用format呢?funcTestFormat(ttesting。T){parse,:template。New()。Parse(packagemainimportfmtfuncmain(){fmt。Println({{。}})})buffer:bytes。Buffer{}parse。Execute(buffer,map{data:1111})source,:format。Source(buffer。Bytes())fmt。Printf(s,source)}RUNTestFormatpackagemainimportfmtfuncmain(){fmt。Println(map〔data:1111〕)}PASS:TestFormat(0。00s)PASS
是不是变得很整齐。总结
go原生的提供了模版机制,对于开发者相当友好,尽管第三方包有很多模版工具,但是原生是最好的,因为不需要引入依赖。
模版通常用于生成一些复用的代码,比如protobuf文件生成,比如orm框架的model,dao等,都是需要改进的参考
https:juejin。impost5c403b98f265da612d1984c9
https:juejin。impost5eb232026fb9a043867d50ae
看谷爱凌冬奥夺金,我不后悔放弃激光电视在北京冬奥会今天白天比赛中,我在电视上见证了谷爱凌最后一跳奠定胜局,为中国在本届冬奥会上再添一金。这台TCL98吋电视120HZ高刷新率MEMC运动防抖技术所带来的画面丝……
独家他加入神童李一男的公司后被并到华为却靠极米创造神话运营商财经实习生李思缘文近日,极米科技携手保时捷设计共同推出极米RSAIR保时捷设计智能投影。纵观整个投影仪市场,极米科技在产品数量、质量和品种方面,都已逐步走向成熟。……
快手招商团长的优势快手于2018年进入电商,2019年快手电商的日活超过1亿,每天新增约10万条电商,且完成了约350亿的交易额,已经超过了快手制定的当年GMV目标。申请v(hscm667788……
大量中国商家离场,亚马逊怎么了?在这个互联网快速发展的时当中,电商行业的发展可以说是顺风顺水,在我国的电商市场规模更是十分巨大。而具体来看,电商行业之中其实也有很多分支,其中跨境电商就是一个主要的版块。所谓的……
黑莓回来了?5G模型即将发布你还记得智能手机品牌黑莓吗?Blackberry是一个因其配备物理QWERTY键盘的独特设计而广受欢迎的品牌。被称为黑莓病的黑莓未能扩展其生态系统,随着智能手机市场的快速……
实际派快看过来,这些七夕好物送爱人最好浪漫派实际派,你属于哪一派?明天就将迎来咱们中国的七夕节,对于浪漫派来说,带上漂亮的玫瑰花和爱人吃一顿浪漫的烛光晚餐,饭后再欢欢喜喜的去电影院看一场唯美的爱情片,仪式感不……
三星老粉再入三星S21,拍照真的很棒,比苹果好,但也有缺点我买的白色的,后壳有点磨砂的手感,很棒!三星的显示真的做的很好,上一个手机s9就非常喜欢,拍照效果也很好,不失真,像素棒棒的,上传的图片是别的手机拍的,还有就是三星真的有在认真……
校园服务小程序专业定制开发校园服务小程序专业团队定制开发校园服务小程序开发,校园服务小程序专业开发,校园服务小程序搭建开发,校园服务软件开发,校园服务软件搭建开发,校园服务小程序专业搭建开发小程序发展的这般快速趋势,这其中在校……
motorolaedgespro由内而外更进一步很少有人注意到,摩托罗拉换了一个新的口号:POWERTOEMPOWER。这个口号,像极了多年前摩托罗拉全盛时期的口号:LIFEMPOWERED。尽管在手机市场里可以算得上……
iOS15Beta5来了,新变化都在这今天凌晨苹果向开发者推出了iOS15。0Beta5版本号为19A5318f距离上一次版本更新时隔14天本次版本更新主要对系统功能进行调整和部分已知问题进行修复。关机后仍可……
华为不再为荷兰提供5G核心网设备据外媒5月21日报道,华为不再为荷兰主要电信运营商的5G核心网提供组件。媒体报道,一年半前,荷兰政府命令电信运营商从其网络中删除不受信任的供应商提供的设备,当时没有明确提……
研究发现人越胖越难通过运动减肥据英国《卫报》网站8月27日报道,研究表明,对肥胖者而言,通过运动减肥似乎更难。研究人员最初认为,我们一天消耗的总能量是各种活动(从养花除草到跑马拉松)所消耗的能量与人体……