Buffalo 模板不支持 Go 原生的局部变量声明(如 {{ $x := 123 }}),因其默认使用 plush 引擎,该引擎无变量赋值机制,仅支持只读上下文与块级作用域(如 with、if),推荐将逻辑前置到 handler 中处理。

Buffalo 模板不支持类似 Go 原生 template 那样的局部变量声明(如 {{ $x := 123 }}),直接写会报错或被忽略。
为什么 Buffalo 模板里不能用 {{ $x := ... }}
Buffalo 默认使用 plush 作为模板引擎,它语法上不兼容 Go 标准库的 text/template 变量绑定语法。你写 {{ $x := "foo" }} 不会报错,但 $x 在后续位置根本不可访问——plush 把它当作了无效表达式静默丢弃。
-
plush的作用域模型是“只读上下文 + 局部作用域块”,没有显式变量赋值机制 - 所有传入模板的数据都来自
context.Data,或通过with、if等块级结构临时改变当前作用域(不是定义新变量) - 试图复用 Go 模板习惯(比如在
range中用$i := $index)会失效
替代方案:用 with 或 if 构造局部作用域
虽然不能“声明变量”,但你可以把计算结果或嵌套结构“提升”为当前块的作用域根对象,达到类似效果:
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
- 用
{{ with .User.Name }}Hello, {{ . }}!{{ end }}—— 此处.就是.User.Name的值,相当于临时绑定了一个“只读局部值” - 用
{{ if $active := eq .Status "active" }}...{{ end }}是无效的;但可以写成{{ if eq .Status "active" }}...{{ end }},再在内部用{{ .Status }}多次引用 - 如果需要多次使用复杂表达式(比如
len .Items),建议提前在 handler 中算好,塞进c.Data["itemCount"] = len(items)
真要动态计算?改用 plush 的 set 动作(有限制)
plush 提供了非标准但可用的 {{ set "key" "value" }},但它只能存字符串字面量或已存在的上下文字段,不支持表达式求值:
-
{{ set "greeting" "Hi there" }}✅ 可用,之后{{ .greeting }}能取到 -
{{ set "count" (len .Items) }}❌ 报错:plush不支持函数调用作为set的右值 -
{{ set "userEmail" .User.Email }}✅ 可用(前提是.User.Email存在且是字符串) -
set定义的键只在当前模板层级生效,子模板({{ yield }}或{{ partial }})拿不到
最稳妥的做法:逻辑前置到 handler
Buffalo 的设计哲学是“模板只负责展示,不负责计算”。所有可能被多次使用的值、条件判断结果、格式化后的内容,都应该在 func(c buffalo.Context) error 里准备好:
- 避免在模板里拼接字符串、调用
time.Now、做len或index操作 - 比如:不要在模板里写
{{ if gt (len .Posts) 5 }},而应在 handler 中设c.Data["hasManyPosts"] = len(posts) > 5 - 这样既提升渲染性能,也避免模板层逻辑膨胀,还能让测试更直接
真正容易被忽略的是:很多人试图在模板里“补救” handler 漏掉的数据准备,结果掉进 set 不支持表达式、with 作用域嵌套混乱、partial 无法访问父级 set 值这些坑里——与其挣扎,不如把那几行 Go 代码挪到 handler 里去。

















