Go的html/template不支持三元运算符,需用{{if}}配合gt/lt等内置比较函数,如{{if gt .Score 90}}high{{else}}low{{end}}。

模板里用 gt / lt 做数值比较,别写内联表达式
Go 的 html/template 不支持三元运算符(比如 {{ .Score > 90 ? "high" : "low" }}),强行拼会编译失败。必须用 {{if}} 块配合内置比较函数:gt(大于)、lt(小于)、eq(等于)、gte(≥)、lte(≤)。它们只接受两个参数,不能链式写(60 是非法的)。
常见错误是试图在模板里做算术或逻辑组合,比如 {{if and (gt .Score 60) (lt .Score 90)}} —— 虽然语法合法,但可读性差、易出错,且无法复用。优先用嵌套 else if 或提前计算好状态值。
直接在 class 属性里写条件块最简单
把样式决策留在模板层,适合逻辑简单、复用少的场景。比如评分展示:
<span class="score {{if gt .Score 90}}text-green{{else if gt .Score 60}}text-yellow{{else}}text-red{{end}}">
{{.Score}}
</span>
这样写清晰、安全、无需额外注册函数。注意:class 属性值必须完整包裹在双引号内,条件块不能拆开;{{end}} 必须闭合,漏掉会导致模板解析失败。
不推荐把判断结果塞进变量再插值,比如 class="{{.ScoreClass}}" ——这会让模板失去语义,且一旦 .ScoreClass 来自用户输入(如 URL 参数),可能引入 XSS 风险。
数值区间多或逻辑重复时,注册自定义模板函数更可控
当多个模板都要根据 .Latency、.Status、.Level 渲染不同 class,硬编码一堆 {{if}} 会让模板臃肿难维护。这时应在 Go 代码中注册一个函数:
func scoreClass(score int) string {
switch {
case score > 90:
return "text-green"
case score > 60:
return "text-yellow"
default:
return "text-red"
}
}
// 注册到 Gin 的 HTML 模板引擎
r.SetFuncMap(template.FuncMap{"scoreClass": scoreClass})
然后模板里直接用:<span class="{{scoreClass .Score}}">{{.Score}}</span>。好处是逻辑集中、类型安全、便于单元测试;坏处是函数名要全局唯一,且不能访问 c 上下文(比如无法读取 locale)。
注意:自定义函数返回值必须是 string 或能被 template 安全转义的类型;若返回 HTML 片段,需用 template.HTML 包裹,否则会被自动转义。
别在模板里处理用户输入的数值
如果 .Score 来自 query 或 JSON 请求体(比如 c.ShouldBindJSON(&req)),务必先在 Go 层校验其范围和类型。模板不是防线:
-
binding:"required,gte=0,lte=100"确保传入的是合法整数 - 避免
{{if gt .Score -1}}这类无意义判断——负分本身就不该存在 - 前端传
"score": "abc"会导致绑定失败,.Score取零值,模板里gt 90判断为 false,但你根本没意识到数据已损坏
模板只负责“怎么展”,不负责“对不对”。数值合法性必须在进入模板前就确认。


















