Buffalo模板需手动注册runeLen函数统计真实字数:app.Templates().AddFunc("runeLen", func(s string) int { return utf8.RuneCountInString(s) }),并确保在Load()前完成;更推荐在action层预计算后传入模板。

Buffalo 模板里没有内置字数统计函数
Buffalo 的 html/template 引擎(底层基于 Go 标准库)不提供类似 len 直接计算中文字符数的语义支持——len 对字符串返回的是 UTF-8 字节数,不是用户感知的“字数”。比如一个汉字占 3 字节,len("好") 是 3,但字数是 1。
用 strings.RuneCountInString 才算真正字数
Go 中正确统计 Unicode 字符个数(即“几个字”)必须用 strings.RuneCountInString,它按 rune(Unicode 码点)计数,对中英文、Emoji 都准确。
Buffalo 模板默认不暴露这个函数,需手动注册为模板函数:
app.Templates().AddFunc("runeLen", func(s string) int {
return utf8.RuneCountInString(s)
})
注意要先 import "unicode/utf8";别用 strings 包,Buffalo 模板函数注册时不能带包名前缀。
注册后,在模板中即可使用:
{{ runeLen .Title }} 字
常见错误:误用 len 或 strings.Count
-
len .Content→ 返回字节数,中文内容会严重高估(如 “你好” 显示为6) -
{{ strings.Count .Content " " }}→ 只能数空格,不是字数 - 在模板里调用未注册的自定义函数(如直接写
runeLen)→ 模板编译失败,报错function "runeLen" not defined - 注册函数时用了变量名或闭包捕获外部状态 → Buffalo 启动时报 panic,因模板函数必须是纯函数
更安全的做法:提前算好传入模板
如果字数只用于展示(比如「已输入 24 字」),推荐在 action 层就计算好,避免模板逻辑膨胀:
func (c buffalo.Context) Show(c buffalo.Context) error {
content := c.Param("content")
c.Set("charCount", utf8.RuneCountInString(content))
return c.Render(200, r.HTML("show.html"))
}
模板里直接用 {{ .charCount }} 即可。这样既规避了模板函数注册的麻烦,也利于单元测试和复用。
真正容易被忽略的是:Buffalo 的模板函数注册必须在 app.go 初始化阶段完成,且不能晚于 app.Templates().Load() 调用——否则函数不可见。

















