Golang模板中使用嵌套变量的方法与技巧

Golang模板中使用嵌套变量的方法与技巧 在我的第一个版本中,我刚刚实现了一个函数来插值类似这样的内容:

"{{ .house }} {{ .cosa_rara | upper }} ",使用了以下映射:

varsContent := map[string]interface{}{
    "mix":       "{{ .house }}  {{ .cosa_rara | upper  }} ",
    "house":     "A {{ .the }} casita",
    "the":       "la {{ .cosa_rara | title  }}",
    "animal":    "de {{ .the | title }} mariposa",
    "cosa_rara": "demo_pato",
    "mapa":      "demo_pato",
    "cyclic":    "This is a {{ .cyclic }}",
    "colour": map[string]interface{}{
        "red":    "rojo",
        "blue":   "azul",
        "pink":   "rosa",
        "orange": "{{ mapa }}",
    },
}

这次执行的结果是:"A la Demo_pato casita DEMO_PATO "。如你所见,插值是递归执行的,并且工作正常。我现在的问题是,需要实现一种方法来执行这个:"{{ .colour.orange }}",这次执行的结果应该是 “demo_pato”,而在这个问题上……我需要帮助。

非常感谢。


更多关于Golang模板中使用嵌套变量的方法与技巧的实战教程也可以访问 https://www.itying.com/category-94-b0.html

4 回复

你好,何塞,你有代码的链接吗?

更多关于Golang模板中使用嵌套变量的方法与技巧的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


很抱歉,我想我刚刚找到了一个简单得多的解决方案。感谢您抽出时间!!!

你好,

这是测试 https://github.com/judoDsl/interpolator/blob/40d981f685b1447ae1a1720bd0e3c2f18d9973c7/main_test.go#L129

谢谢!!

在Go模板中访问嵌套变量(如{{ .colour.orange }})时,需要确保数据结构支持点号.导航。根据你提供的varsContent结构,colour是一个嵌套的map[string]interface{},但orange的值是字符串"{{ mapa }}",这会导致模板引擎将其视为字面字符串而非模板表达式。以下是实现方法:

1. 修正数据结构

colour.orange的值改为直接引用变量(如"demo_pato")或通过模板函数解析。但根据你的需求,若希望{{ .colour.orange }}输出"demo_pato",需要确保mapa变量能被访问。当前mapa在根层级,但colour.orange是字符串,不会自动解析内部模板。建议使用自定义模板函数处理嵌套变量。

2. 使用自定义函数解析嵌套变量

注册一个自定义函数(如getVar),在模板中通过函数调用访问嵌套值。示例:

package main

import (
    "bytes"
    "fmt"
    "strings"
    "text/template"
)

func main() {
    // 定义数据
    varsContent := map[string]interface{}{
        "mix":       "{{ .house }}  {{ .cosa_rara | upper }}",
        "house":     "A {{ .the }} casita",
        "the":       "la {{ .cosa_rara | title }}",
        "animal":    "de {{ .the | title }} mariposa",
        "cosa_rara": "demo_pato",
        "mapa":      "demo_pato",
        "cyclic":    "This is a {{ .cyclic }}",
        "colour": map[string]interface{}{
            "red":    "rojo",
            "blue":   "azul",
            "pink":   "rosa",
            "orange": "{{ .mapa }}", // 改为模板表达式
        },
    }

    // 自定义函数:获取嵌套变量值
    funcs := template.FuncMap{
        "getVar": func(m map[string]interface{}, key string) interface{} {
            return m[key]
        },
        "upper": strings.ToUpper,
        "title": strings.Title,
    }

    // 解析模板
    tmplStr := `{{ .colour.orange }}` // 直接访问嵌套map
    tmpl, err := template.New("test").Funcs(funcs).Parse(tmplStr)
    if err != nil {
        panic(err)
    }

    // 执行模板
    var buf bytes.Buffer
    err = tmpl.Execute(&buf, varsContent)
    if err != nil {
        panic(err)
    }
    fmt.Println("输出:", buf.String()) // 输出: {{ .mapa }}
}

但上述代码中,colour.orange是字符串"{{ .mapa }}",输出会是字面量而非解析后的"demo_pato"。这是因为模板引擎不会递归解析字符串内的模板语法。

3. 递归解析解决方案

若要实现递归解析,需在自定义函数中处理模板字符串。示例:

funcs := template.FuncMap{
    "resolve": func(data map[string]interface{}, s string) (string, error) {
        tmpl, err := template.New("resolver").Funcs(funcs).Parse(s)
        if err != nil {
            return "", err
        }
        var buf bytes.Buffer
        err = tmpl.Execute(&buf, data)
        return buf.String(), err
    },
}

// 在模板中使用:{{ resolve . "{{ .colour.orange }}" }}

但更直接的方法是预处理数据,将colour.orange的值改为变量引用而非字符串模板。例如:

varsContent["colour"].(map[string]interface{})["orange"] = varsContent["mapa"]

然后模板{{ .colour.orange }}将直接输出"demo_pato"

4. 完整示例:预处理嵌套值

package main

import (
    "bytes"
    "fmt"
    "strings"
    "text/template"
)

func main() {
    varsContent := map[string]interface{}{
        "mapa": "demo_pato",
        "colour": map[string]interface{}{
            "orange": nil, // 先占位
        },
    }
    // 预处理:将colour.orange指向mapa的值
    varsContent["colour"].(map[string]interface{})["orange"] = varsContent["mapa"]

    funcs := template.FuncMap{
        "upper": strings.ToUpper,
        "title": strings.Title,
    }

    tmpl, _ := template.New("test").Funcs(funcs).Parse(`{{ .colour.orange }}`)
    var buf bytes.Buffer
    tmpl.Execute(&buf, varsContent)
    fmt.Println("输出:", buf.String()) // 输出: demo_pato
}

关键点

  • Go模板默认支持通过点号.访问嵌套map的字段(如{{ .colour.orange }}),但值必须是具体数据而非含模板语法的字符串。
  • 若需动态解析嵌套模板字符串,需通过自定义函数递归处理或预处理数据结构。
  • 你的案例中,将colour.orange的值直接设为varsContent["mapa"]是最简洁的解决方案。
回到顶部