// 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 。
1
matrix1010 269 天前
文档里的第一个例子就很清楚: https://pkg.go.dev/text/template. 不返回就没法继续执行了。Templates can be redefined in successive calls to Parse 是说可以多次 call `Parse`来重用,跟返回什么关系不大
|
2
Kinnice 269 天前
比如加密模版?
|
3
flyqie 269 天前 via Android
能复用还是尽量复用的比较好,template 这种复用需求还是有不少的。
|
4
uniquecolesmith 269 天前
确实如此,你思考的很深,去掉也可以的,应该只是设计者一开始的设计一直延续,用多了就不好改
每日分享 Go / 云原生 / Python / 前端等开源技术,有兴趣的可以加我,附上你的职位,我拉你进相关微信分享群,这里只做开源技术分享,加我 (wechat: _whatwewant_) |
5
uniquecolesmith 269 天前
@yujianwjj 这个问题在群里问,有更多大佬为你解答
|
6
bv 269 天前
前 3L 不知道想表达什么,我个人觉得这么定义 func (t *Template) Parse(text string) error 确实可行,但不清除设计这个接口时为何要返回 *Template
|
7
GenericT 269 天前
go 不就是这个风格,a := append(a,b)
|
8
baiyi 269 天前
这个写法是为了方便链式调用的,你看下 template 的其他方法,也都是返回了同样值。
返回了 err 的话不能直接进行调用,但可以通过 template.Must 这种方式写成一行。 使用的时候可以这么写:template.Must(template.New("prog").Parse(prog)).Execute(&buf, v) |
9
yujianwjj OP append 这个风格是因为可能会触发底层数组扩容,重新分配数组,所以设计成这个样子。
|
10
maocat 269 天前 via iPhone
8 楼说的才是对的,你看源码顶上有个 Must 方法,给你链式调用用的
|
12
evercyan 268 天前
@bv #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 } |
15
bv 268 天前
我的疑惑就是:如果 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 } |
16
evercyan 268 天前
@bv #15
链式的实现是每次调用都返回自身, 也就是 *Template, 实现 t.A().B().C(), 不然如果 A() 执行返回了 error, 还能 err.B().C() 么, 但是如果 A() 执行确实有需要抛出去的 error 怎么办, 那就只能搞个 Must 了, 当然并不是说这个返回就一定是为了链式调用而设计的, |
17
bv 268 天前
@evercyan 感谢,这个规则我明白,Parse(text string) (*Template, error) 反响适配 Must 感觉很奇怪,我感觉 #15 的 Must 写法也不影响 Must 链式调用。
|
18
evercyan 268 天前
@bv #17 这种在 Must 里去做 Parse 没看懂是什么逻辑, 如果还有一个 Parse1 呢,
这里的 Must 其实都可以抽成公共函数用泛型去实现了, 本身不带业务逻辑的, 就单纯判断最后一个入参是 error 就 panic, 不是就返回第一个 Any, |
19
matrix1010 268 天前
再详细说说: 1. 为什么返回 (*Template, error), 因为这样 API 更简洁。比如 templates["index"] = template.Must(template.Parse("xxxxx")),直接一行写完. 2. 什么情况下会重复 call Parse: Parse 方法调用时的实际情况取决于你传入的 string, 当 template 本身是动态的情况下可能会在运行时 parse ,很多可以客户定制的低代码平台应该都有这类功能。可以看我写的这个例子: https://go.dev/play/p/rE7IDfsPBLp
|