buffalo 模板传切片必须确保类型明确且字段导出:结构体字段首字母大写,切片直接通过 c.set("key", slice) 传入,模板中用 {{range .key}} 遍历;禁用 []interface{} 和未导出字段,避免渲染为空或报错。

Buffalo 模板里传切片,核心就一条:确保类型明确、结构可序列化,别用 interface{} 包一层
为什么 c.Render() 传切片会报错或渲染为空
常见错误是直接传 []interface{} 或未导出字段的结构体切片,比如 []user(其中 user 是小写首字母的 struct)。Buffalo 的模板引擎基于 Go 标准 html/template,它只访问导出字段(大写首字母),且对 interface{} 类型不做深度反射。
- 传
[]interface{}→ 模板里{{.}}显示空,因为没导出字段可渲染 - 传
[]User但User字段全小写 → 模板无法读取任何值 - 在
actions中用map[string]interface{}包裹切片再传 → 多余,反而增加类型擦除风险
正确传递切片的两种方式
推荐显式定义结构体类型,避免运行时类型模糊:
Buffalo框架 1.0.1 版本源码包下载,适合需要错误处理改进、依赖更新、render.Download 注释和 request logger 调整的 v1 项目。
- 定义导出结构体,字段首字母大写:
type Post struct { ID int `json:"id"` Title string `json:"title"` } - 在 handler 中构造切片并直接传入:
func PostsHandler(c buffalo.Context) error { posts := []Post{ {ID: 1, Title: "Hello"}, {ID: 2, Title: "World"}, } return c.Render(200, r.HTML("posts/index.html")) }注意:切片变量名要通过c.Set()注入上下文,否则模板拿不到:c.Set("posts", posts)
模板中遍历切片的写法和常见坑
Buffalo 模板语法和标准 Go template 一致,但容易忽略两点:空切片判断和字段访问权限。
- 用
{{if .posts}}判断非空,不是{{if .posts != nil}}(.posts在空切片时为[],不为nil) - 遍历时必须用点号访问字段:
{{range .posts}} {{.Title}} {{end}},不能写成{{.Title}}(那是访问切片本身) - 如果需要索引,用
{{range $i, $p := .posts}},然后{{$i}}和{{$p.Title}} - 避免在模板里调用方法(如
{{.CreatedAt.Format "2006-01-02"}}),除非该方法在 action 层已预处理好字符串
复杂嵌套切片(比如带关联数据)怎么传
不要在模板里做 join 或 map 查找。Buffalo 强调「逻辑在 action,展示在 template」。例如文章带标签列表:
- 在 handler 中提前组装好结构:
type PostWithTags struct { Post Post Tags []string } postsData := []PostWithTags{ {Post: p1, Tags: []string{"go", "web"}}, } - 再
c.Set("posts", postsData),模板里就能安全{{range .posts}} {{.Post.Title}} {{range .Tags}}#{{.}} {{end}} {{end}} - 切忌把
*pop.Connection或context.Context传进模板 —— Buffalo 不允许,运行时报template: can't evaluate field XXX
真正卡住人的往往不是语法,而是误以为模板能“智能推断”类型。Buffalo 的渲染链路很直:action 构造什么,就传什么;传什么,模板就收什么。多一层转换(比如转 map 再转切片),就多一分 runtime panic 风险。










