Go模板中len是内置函数,可直接用于切片、数组等,但对nil会panic;需先判空(如{{if .Items}}{{len .Items}}{{else}}0{{end}}),且range内访问根变量须用$.Items。

Go模板里用 len 函数判断数组或切片长度
Revel 框架默认使用 Go 原生模板引擎,不支持自定义函数注入(除非手动注册),但 len 是模板内置函数,可直接用。注意它只适用于切片、数组、map、chan、字符串 —— 对 nil 切片或未初始化变量调用会 panic。
常见错误现象:template: xxx:xxx: error calling len: len of untyped nil,多因传入的 .DataList 是 nil 而非空切片。
- 确保控制器中传值是初始化过的切片,比如
c.RenderArgs["items"] = []string{},而非nil - 模板中先判空再取长度更安全:
{{if .Items}}{{len .Items}}{{else}}0{{end}} - 若需在
range中提前知道长度(如分页显示“共 N 条”),必须单独用len,不能依赖$index
Revel 模板里 range 不提供原生长度变量
Go 模板的 range 只暴露 $index 和 $value,没有类似 $length 或 $first/$last 的内置变量。想在循环内判断是否是最后一条?得靠 len 配合 $index 手动算:
{{range $i, $item := .Items}}
{{if eq (sub (len $.Items) 1) $i}}这是最后一条{{end}}
{{end}}
注意这里用了 $.Items(带 $ 表示根作用域),因为 range 内部作用域已切换,.Items 会解析失败。
-
sub是 Revel 默认注册的数学函数(Go 模板原生不带),所以能用;标准 Go 模板里得预计算好传入 - 如果不用
sub,就只能在控制器里算好c.RenderArgs["itemsLen"] = len(items),模板里直接用{{.itemsLen}} - 别在模板里嵌套调用
len太多次——虽无性能瓶颈,但可读性差,且容易漏掉$导致作用域错误
传 nil 切片进模板导致 len 报错怎么办
Revel 控制器里如果写 c.RenderArgs["list"] = nil,模板里 {{len .list}} 直接崩溃,错误信息是 error calling len: len of untyped nil。这不是 Revel 特有,是 Go 模板规范行为。
- 最稳妥做法:控制器中统一转成空切片,例如
c.RenderArgs["list"] = append([]string(nil), data...)或显式初始化[]string{} - 模板里防御性写法:
{{if .list}}{{len .list}}{{else}}0{{end}},但注意{{if .list}}对 nil 切片为 false,对空切片为 true,刚好区分 - 避免用
reflect.ValueOf(.list).Kind == reflect.Slice这类反射判断——模板不支持反射调用,Revel 也没注册相关函数
len 看似简单,真正卡住人的往往是 nil vs 空切片的语义差异,以及作用域切换后变量访问方式的变化。写模板时多看一眼传入值是不是可能为 nil,比事后查 panic 日志快得多。


















