golang template模板嵌套语法 为何不能使用变量 底层源码解析

我们都知道在golang的模板语法中,我们可以使用template关键字嵌套其他模块, 如: {{template "模板文件名" .}}  然而,这里的 “模板文件名”  是不能使用变量的!  注意这里最后的的  .   这个实际上是template关键字的第二个参数, 在go的模板里面 它代表的是当前的所有变量数据,即你在执行渲染模板时的第二个data参数,函数原型 func (t *template.Template) Execute(wr io.Writer, data any) error  了解这点很重要!

底层源码分析

golang的template模板解析底层是通过一个叫做 lexer 的对象来实现的。在lexer里面这里的 template 被作为一个关键字, 和其他的 if  else  end, range ,with等一样的关键字。  而这里的模板名在go底层在解析前就被使用Quote解码了, 即 strconv.Quote(模板文件名),所以你在这里输入的任何变量都不会被解析!

go底层代码见源码文件 /src/text/template/parse/node.go 

template这个关键字的第二个参数的处理代码:

func (t *TemplateNode) writeTo(sb *strings.Builder) {
	sb.WriteString("{{template ")
	sb.WriteString(strconv.Quote(t.Name))
	if t.Pipe != nil {
		sb.WriteByte(' ')
		t.Pipe.writeTo(sb)
	}
	sb.WriteString("}}")
}

lexer模板渲染里面的关键字参考

可以看到这里有我们熟悉的 .   if  else   range with  还有template 这些在golang的模板里面都被用作了关键字

var key = map[string]itemType{
	".":        itemDot,
	"block":    itemBlock,
	"break":    itemBreak,
	"continue": itemContinue,
	"define":   itemDefine,
	"else":     itemElse,
	"end":      itemEnd,
	"if":       itemIf,
	"range":    itemRange,
	"nil":      itemNil,
	"template": itemTemplate,
	"with":     itemWith,
}

lexer模板分隔符解析逻辑和默认分隔符参考

可见对于模板分隔符,如果我们传递的是一个空字符串,则lexer就会使用他自己 定义的常量 {{  }}来作为分隔符

// state functions

const (
	leftDelim    = "{{"
	rightDelim   = "}}"
	leftComment  = "/*"
	rightComment = "*/"
)


// lex creates a new scanner for the input string.
func lex(name, input, left, right string) *lexer {
	if left == "" {
		left = leftDelim
	}
	if right == "" {
		right = rightDelim
	}
	l := &lexer{
		name:         name,
		input:        input,
		leftDelim:    left,
		rightDelim:   right,
		line:         1,
		startLine:    1,
		insideAction: false,
	}
	return l
}

总结:

在go的模板里面,实际上他所有的关键字最终编译器层面基本上都是以函数的方式运行的。  这里的template关键字 的第二个参数在递交编译器之前被 Quote 了一把, 所以这里任何的变量都不会被解析,从而导致了template模板嵌套语法 不能使用任何的变量! 

  • 5
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值