必须在app/init.go的init()函数中注册,且函数名首字母大写、签名合规(导出、参数类型精确、返回值最多两个且第二个为error或template.HTML),否则模板调用报“function not defined”。

必须在 app/init.go 的 init() 函数中注册,且函数名必须首字母大写、签名合规,否则模板里调用会报 function "xxx" not defined。
Revel 模板函数注册位置固定在 app/init.go
Revel 不像原生 html/template 那样允许你在任意地方创建新模板实例并挂载函数。它要求所有自定义模板函数统一在框架初始化阶段注入:
-
revel.TemplateFuncs是一个全局map[string]interface{},只在app/init.go的init()里可安全写入 - 注册代码必须放在
revel.InterceptFunc、revel.BEFORE等拦截器注册之后,但早于revel.Run()启动前 - 常见错误:在 controller 里临时注册(无效)、在
views/某个模板文件里写func(Go 语法不支持)
revel.TemplateFuncs 的函数签名限制很严
你塞进去的函数不是随便写的 Go 函数,模板引擎会在运行时用反射调用,稍有不匹配就 panic 或静默丢弃:
- 函数必须导出(首字母大写),例如
FormatTime✅,formatTime❌ - 参数类型必须精确匹配模板传入值的底层类型,比如字段是
time.Time,函数就得声明func FormatTime(t time.Time) string,不能收interface{}再强转 - 返回值最多两个,第二个要是
error类型;若想输出 HTML 片段,返回template.HTML类型避免被二次转义 - 别在函数里
panic——模板会吞掉它,只输出空字符串,无日志、无提示
注册后模板里怎么调用?注意作用域和大小写
注册进 revel.TemplateFuncs 的函数,在所有 Revel 模板(.html 文件)中全局可用,但调用名必须和 map key 完全一致:
- 注册写的是
revel.TemplateFuncs["ftime"] = FormatTime,模板里就得写{{ftime .CreatedAt}},不是{{FormatTime}}也不是{{Ftime}} - Revel 内置函数(如
eq、set、field)和你注册的函数共存,无优先级冲突 - 如果函数返回
template.HTML,记得确保内容可信,否则绕过转义可能引入 XSS - 调试技巧:在模板里先
{{printf "%#v" .CreatedAt}}确认传入值的真实类型,再决定函数怎么写
最容易被忽略的是:函数注册时机不可逆,且 revel.TemplateFuncs 是全局 map —— 如果多个模块都往里面塞同名 key,后注册的会覆盖前一个,而 Revel 不报任何警告。


















