Revel框架需自定义truncate函数实现安全截断,因标准模板不支持切片语法且len返回字节数易致中文乱码,必须按rune计数并注册到TemplateFuncs。

Revel 框架本身不提供内置的文本截断函数(如 truncate),必须靠自定义模板函数实现,否则直接用 substr 或切片会 panic 或乱码。
为什么不能直接用 substr 或 [0:20]
Go 标准 html/template 不支持字符串切片语法;substr 是某些第三方模板引擎的函数,在 Revel 默认环境里不存在。硬写 {{.Title[0:20]}} 会导致编译失败:can't evaluate field 0 in type string。
- 字符串长度判断必须用
len函数,但len返回字节数,对中文/emoji 不友好 - 若未做 UTF-8 安全处理,截断可能落在字符中间,渲染出 符号
- Revel 模板作用域中无法调用 Go 的
utf8.RuneCountInString等原生函数
正确做法:注册安全的 truncate 自定义函数
在 app/init.go 的 init() 函数中注册一个能按 rune 截断的函数:
revel.TemplateFuncs["truncate"] = func(s string, n int) string {
if n
- 必须用
[]rune(s)而非[]byte(s),否则中文会被错误截断 - 返回值末尾加
"…"是可选但推荐的 UX 提示 - 该函数需重启 Revel 服务才生效,热重载不触发模板函数重载
模板中怎么用:参数顺序和空值防御
调用时注意传参顺序和空值保护,避免 nil panic:
{{if .Title}}{{truncate .Title 30}}{{else}}无标题{{end}}
-
.Title为nil或空字符串时,truncate函数内部不会 panic,但最好外层加{{if}}判空 - 数字字面量必须写整数,不能写变量名(除非该变量已通过
set注入) - 不要写成
{{truncate 30 .Title}}—— 参数顺序错会导致截断结果异常或静默失败
最易被忽略的是 rune vs byte 的差异:一个中文字符占 3 字节,但只算 1 个 rune。用字节切片截 30 字节,可能只显示 10 个汉字还带乱码;而 truncate 按 rune 截 30,才能稳定输出 30 个可读字符。











