Golang模板(以及将函数传递给模板)

huangapple go评论88阅读模式
英文:

Golang templates (and passing funcs to template)

问题

当我尝试访问我传递给模板的函数时,出现了错误:

错误信息:template: struct.tpl:3: 未定义函数"makeGoName"

请问有人可以告诉我我做错了什么吗?

模板文件(struct.tpl):

type {{.data.tableName}} struct {
{{range $key, $value := .data.tableData}}
{{makeGoName $value.colName}} {{$value.colType}} db:"{{makeDBName $value.dbColName}},json:"{{$value.dbColName}}"
{{end}}
}

调用文件:

type tplData struct {
tableName string
tableData interface{}
}

func doStuff() {
t, err := template.ParseFiles("templates/struct.tpl")
if err != nil {
errorQuit(err)
}

t = t.Funcs(template.FuncMap{
	"makeGoName": makeGoName,
	"makeDBName": makeDBName,
})

data := tplData{
	tableName: tableName,
	tableData: tableInfo,
}

t.Execute(os.Stdout, data)

}

func makeGoName(name string) string {
return name
}

func makeDBName(name string) string {
return name
}

这是一个生成结构体样板代码的程序(如果有人想知道为什么我在模板中这样做)。

英文:

I'm getting an error when I try and access a function I'm passing to my template:

Error: template: struct.tpl:3: function "makeGoName" not defined

Can anyone please let me know what I'm doing wrong?

Template file (struct.tpl):

type {{.data.tableName}} struct {
  {{range $key, $value := .data.tableData}}
  {{makeGoName $value.colName}} {{$value.colType}} `db:"{{makeDBName $value.dbColName}},json:"{{$value.dbColName}}"`
  {{end}}
}

Calling file:

type tplData struct {
	tableName string
	tableData interface{}
}

func doStuff() {
	t, err := template.ParseFiles("templates/struct.tpl")
	if err != nil {
		errorQuit(err)
	}

	t = t.Funcs(template.FuncMap{
		"makeGoName": makeGoName,
		"makeDBName": makeDBName,
	})

	data := tplData{
		tableName: tableName,
		tableData: tableInfo,
	}

	t.Execute(os.Stdout, data)
}

func makeGoName(name string) string {
	return name
}

func makeDBName(name string) string {
	return name
}

This is for a program that generates struct boilerplate code (in case anyone is wondering why I'm doing that in my template).

答案1

得分: 26

自定义函数需要在解析模板之前进行注册,否则解析器将无法确定标识符是否为有效的函数名。模板被设计为可以静态分析,这是对其的要求。

你可以首先使用template.New()创建一个新的未定义模板,除了template.ParseFiles()函数外,template.Template类型(由New()返回)还有一个Template.ParseFiles()方法,你可以调用它。

像这样:

t, err := template.New("").Funcs(template.FuncMap{
    "makeGoName": makeGoName,
    "makeDBName": makeDBName,
}).ParseFiles("templates/struct.tpl")

请注意,template.ParseFiles()函数在内部也调用了template.New(),将第一个文件的名称作为模板名称传递。

另外,Template.Execute()返回一个error,可以打印出来查看是否生成了输出,例如:

if err := t.Execute(os.Stdout, data); err != nil {
    fmt.Println(err)
}
英文:

Custom functions need to be registered before parsing the templates, else the parser would not be able to tell whether an identifier is a valid function name or not. Templates are designed to be statically analyzable, and this is a requirement to that.

You can first create a new, undefined template with template.New(), and besides the template.ParseFiles() function, the template.Template type (returned by New()) also has a Template.ParseFiles() method, you can call that.

Something like this:

t, err := template.New("").Funcs(template.FuncMap{
	"makeGoName": makeGoName,
	"makeDBName": makeDBName,
}).ParseFiles("templates/struct.tpl")

Note that the template.ParseFiles() function also calls template.New() under the hood, passing the name of the first file as the template name.

Also Template.Execute() returns an error, print that to see if no output is generated, e.g.:

if err := t.Execute(os.Stdout, data); err != nil {
    fmt.Println(err)
}

答案2

得分: 7

在为模板注册自定义函数并使用ParseFiles()时,需要在实例化和执行模板时指定模板的名称。在调用Funcs()之后,还需要调用ParseFiles()

// 使用自定义函数创建一个命名模板
t, err := template.New("struct.tpl").Funcs(template.FuncMap{
    "makeGoName": makeGoName,
    "makeDBName": makeDBName,
}).ParseFiles("templates/struct.tpl") // 解析模板文件
if err != nil {
    errorQuit(err)
}

// 执行命名模板
err = t.ExecuteTemplate(os.Stdout, "struct.tpl", data)
if err != nil {
    errorQuit(err)
}

在使用命名模板时,名称是不包含目录路径的文件名,例如struct.tpl而不是templates/struct.tpl。因此,在New()ExecuteTemplate()中的名称应该是字符串struct.tpl

英文:

When registering custom functions for your template and using ParseFiles() you need to specify the name of the template when instantiating it and executing it. You also need to call ParseFiles() after you call Funcs().

// Create a named template with custom functions
t, err := template.New("struct.tpl").Funcs(template.FuncMap{
    "makeGoName": makeGoName,
    "makeDBName": makeDBName,
}).ParseFiles("templates/struct.tpl") // Parse the template file
if err != nil {
    errorQuit(err)
}

// Execute the named template
err = t.ExecuteTemplate(os.Stdout, "struct.tpl", data)
if err != nil {
    errorQuit(err)
}

When working with named templates the name is the filename without the directory path e.g. struct.tpl not templates/struct.tpl. So the name in New() and ExecuteTemplate() should be the string struct.tpl.

huangapple
  • 本文由 发表于 2016年2月22日 17:45:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/35550326.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定