Golang Go语言 template 源码的一个疑问
// Parse parses text as a template body for t.
// Named template definitions ({{define ...}} or {{block ...}} statements) in text
// define additional templates associated with t and are removed from the
// definition of t itself.
//
// Templates can be redefined in successive calls to Parse.
// A template definition with a body containing only white space and comments
// is considered empty and will not replace an existing template's body.
// This allows using Parse to add new named template definitions without
// overwriting the main template body.
func (t *Template) Parse(text string) (*Template, error) {
t.init()
t.muFuncs.RLock()
trees, err := parse.Parse(t.name, text, t.leftDelim, t.rightDelim, t.parseFuncs, builtins())
t.muFuncs.RUnlock()
if err != nil {
return nil, err
}
// Add the newly parsed trees, including the one for t, into our common structure.
for name, tree := range trees {
if _, err := t.AddParseTree(name, tree); err != nil {
return nil, err
}
}
return t, nil
}
我认为应该是下面这样,返回值没必要加原来的 *Template
。
func (t *Template) Parse(text string) error
注释里面写了 Templates can be redefined in successive calls to Parse.
但是没明白什么场景会 redefined 。
Golang Go语言 template 源码的一个疑问
更多关于Golang Go语言 template 源码的一个疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
文档里的第一个例子就很清楚: https://pkg.go.dev/text/template. 不返回就没法继续执行了。Templates can be redefined in successive calls to Parse 是说可以多次 call Parse
来重用,跟返回什么关系不大
更多关于Golang Go语言 template 源码的一个疑问的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
比如加密模版?
能复用还是尽量复用的比较好,template 这种复用需求还是有不少的。
确实如此,你思考的很深,去掉也可以的,应该只是设计者一开始的设计一直延续,用多了就不好改
每日分享 Go / 云原生 / Python / 前端等开源技术,有兴趣的可以加我,附上你的职位,我拉你进相关微信分享群,这里只做开源技术分享,加我 (wechat: whatwewant)
这个问题在群里问,有更多大佬为你解答
前 3L 不知道想表达什么,我个人觉得这么定义 func (t *Template) Parse(text string) error 确实可行,但不清除设计这个接口时为何要返回 *Template
go 不就是这个风格,a := append(a,b)
这个写法是为了方便链式调用的,你看下 template 的其他方法,也都是返回了同样值。
返回了 err 的话不能直接进行调用,但可以通过 template.Must 这种方式写成一行。
使用的时候可以这么写:template.Must(template.New(“prog”).Parse(prog)).Execute(&buf, v)
append 这个风格是因为可能会触发底层数组扩容,重新分配数组,所以设计成这个样子。
8 楼说的才是对的,你看源码顶上有个 Must 方法,给你链式调用用的
你确定是因为为了链式调用,Parse 返回了 (*Template, error) 两个参数,还怎么做链式调用?
#11
// Must is a helper that wraps a call to a function returning (*Template, error)
// and panics if the error is non-nil. It is intended for use in variable initializations
// such as
//
// var t = template.Must(template.New(“name”).Parse(“html”))
func Must(t *Template, err error) *Template {
if err != nil {
panic(err)
}
return t
}
你能不能去看看源码啊,示例都摆在源码的头上了
看到了,通过 Must 调用确实可以做到链式调用。但是这么设计总感觉是本末倒置呀。
我的疑惑就是:如果 Parse 不返回 *Template ,也不影响 Must 的链式调用。
func Must(t *Template, s string) *Template {
if err := t.Parse(s); err != nil {
panic(err)
}
return t
}
type Template struct{}
func (t *Template) Parse(s string) error {
return nil
}
#15
链式的实现是每次调用都返回自身, 也就是 *Template, 实现 t.A().B().C(),
不然如果 A() 执行返回了 error, 还能 err.B().C() 么,
但是如果 A() 执行确实有需要抛出去的 error 怎么办, 那就只能搞个 Must 了,
当然并不是说这个返回就一定是为了链式调用而设计的,
感谢,这个规则我明白,Parse(text string) (*Template, error) 反响适配 Must 感觉很奇怪,我感觉 #15 的 Must 写法也不影响 Must 链式调用。
#17 这种在 Must 里去做 Parse 没看懂是什么逻辑, 如果还有一个 Parse1 呢,
这里的 Must 其实都可以抽成公共函数用泛型去实现了, 本身不带业务逻辑的,
就单纯判断最后一个入参是 error 就 panic, 不是就返回第一个 Any,
再详细说说: 1. 为什么返回 (*Template, error), 因为这样 API 更简洁。比如 templates[“index”] = template.Must(template.Parse(“xxxxx”)),直接一行写完. 2. 什么情况下会重复 call Parse: Parse 方法调用时的实际情况取决于你传入的 string, 当 template 本身是动态的情况下可能会在运行时 parse ,很多可以客户定制的低代码平台应该都有这类功能。可以看我写的这个例子: https://go.dev/play/p/rE7IDfsPBLp
当然,很高兴能帮助解答关于Go语言template源码的疑问。
在Go语言的template包中,模板(template)是一种用于生成文本输出的强大工具,它允许你嵌入动态数据到静态文本中。如果你对template源码有具体的疑问,这里有几个可能的切入点来帮助你理解:
-
模板解析:template源码的核心在于模板的解析和执行。解析阶段会将模板文本转换为一种内部表示(即解析树),这个过程会识别模板中的变量、动作(如
{{if}}
、{{range}}
等)以及静态文本。 -
数据执行:一旦模板被解析,它就可以与给定的数据一起执行。这个过程中,模板引擎会遍历解析树,并根据数据动态生成输出。例如,对于
{{.Name}}
这样的变量引用,模板引擎会查找数据结构中名为Name
的字段,并将其值插入到输出中。 -
错误处理:template源码中也包含了详细的错误处理逻辑。如果在解析或执行模板时遇到错误(如语法错误、数据访问错误等),模板引擎会记录这些错误,并在适当的时机返回给调用者。
-
扩展性:Go的template包还提供了扩展机制,允许开发者定义自己的函数和块操作,这进一步增强了模板的灵活性和功能。
如果你有更具体的问题,比如关于某个特定函数或数据结构的实现细节,请提供更多信息,以便我能给出更准确的解答。