一个 Golang 模板函数是否可以在引用自身的同时渲染另一个模板?

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

Is it possible for a Golang template function to render another template while referring to itself?

问题

我想要扩展默认的Golang模板函数,添加一个模板函数,该函数可以渲染另一个Golang模板,并且该模板也应该能够访问该函数。

以下演示案例应该创建一个名为include的模板函数,该函数可以渲染给定的模板,该模板也可以包含相同的include函数。然而,这个例子(正确地)引发了一个初始化循环错误。

Golang模板函数是否可以在渲染另一个模板时引用自身?

package main

import (
	"bytes"
	"errors"
	html_template "html/template"
	"os"
)

var includeFuncs = map[string]interface{}{
	"include": func(templatePath string, data interface{}) (string, error) {
		templatePath = "templates/" + templatePath
		if _, err := os.Stat(templatePath); err != nil {
			return "", errors.New("Unable to find the template file " + templatePath)
		}

		var renderedTpl bytes.Buffer
		tpl, err := html_template.New(templatePath).Funcs(GetHTMLIncludeFuncs()).Parse(templatePath)
		if err != nil {
			return "", err
		}

		if err := tpl.Execute(&renderedTpl, data); err != nil {
			return "", err
		}

		return renderedTpl.String(), nil
	},
}

func GetHTMLIncludeFuncs() html_template.FuncMap {
	return html_template.FuncMap(includeFuncs)
}
英文:

I want to extend the default Golang template functions with a template function that renders another Golang template while that template also should have access to the function in question.

The following demonstration case should create an include template function that renders a given template which could also include the same include function. The example, however (rightfully) raises an initialization cycle error.

Is it possible for a Golang template function to render another template while referring to itself?

https://play.golang.org/p/hml-GDhV1HI

package main

import (
	"bytes"
	"errors"
	html_template "html/template"
	"os"
)

var includeFuncs = map[string]interface{}{
	"include": func(templatePath string, data interface{}) (string, error) {
		templatePath = "templates/" + templatePath
		if _, err := os.Stat(templatePath); err != nil {
			return "", errors.New("Unable to find the template file " + templatePath)
		}

		var renderedTpl bytes.Buffer
		tpl, err := html_template.New(templatePath).Funcs(GetHTMLIncludeFuncs()).Parse(templatePath)
		if err != nil {
			return "", err
		}

		if err := tpl.Execute(&renderedTpl, data); err != nil {
			return "", err
		}

		return renderedTpl.String(), nil
	},
}

func GetHTMLIncludeFuncs() html_template.FuncMap {
	return html_template.FuncMap(includeFuncs)
}

答案1

得分: 1

使用init()

var includeFuncs = map[string]interface{}{}

func includeFunc(templatePath string, data interface{}) (string, error) {...}

func init() {
   includeFuncs["include"]=includeFunc
}

在原始帖子中,你陷入了一个初始化循环,因为在执行开始之前,运行时必须初始化所有已初始化的变量,而编译器检测到了初始化循环。

通过上述解决方案,初始化可以在程序开始之前完成,因为函数映射为空。在main开始运行之前,init函数运行并使用该函数初始化映射。

英文:

Use init():

var includeFuncs = map[string]interface{}{}

func includeFunc(templatePath string, data interface{}) (string, error) {...}

func init() {
   includeFuncs["include"]=includeFunc
}

In the original post, you fall into an initialization loop because before the execution starts, the runtime has to initialize all initialized variables, and the compiler detects the initialization loop.

With the above solution, the initialization can complete before the program starts because the function map is empty. Before main starts running, the init function runs and initializes the map with the function.

huangapple
  • 本文由 发表于 2021年9月21日 03:24:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/69259822.html
匿名

发表评论

匿名网友

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

确定