Golang中{{range.}}为什么不起作用?

Golang中{{range.}}为什么不起作用? 我正在尝试理解HTML模板如何与JSON配合工作。找到了一个示例:

https://play.golang.org/p/EOVypH5ONHn

…并尝试向其添加 {{range.}},但出现了错误:

https://play.golang.org/p/vrwx01z0_0o

package main

import (
	"encoding/json"
	"html/template"
	"os"
)

func main() {
	t := template.Must(template.New("").Parse(templ))

	m := map[string]interface{}{}
	if err := json.Unmarshal([]byte(jsondata), &m); err != nil {
		panic(err)
	}

	if err := t.Execute(os.Stdout, m); err != nil {
		panic(err)
	}
}

const templ = `<html><body>
        {{range.}}	
	      {{.something}}
	      {{.somethingElse}}
        {{end}}
</body></html>`

const jsondata = `{"something":"valueofa", "somethingElse": 1234}`

我哪里做错了?为什么没有 {{range.}} 时它可以正常工作?


更多关于Golang中{{range.}}为什么不起作用?的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

请注意,该模板处理的是 JSON 数组。即使你只有一个 JSON 对象,也必须将其包装成 JSON 数组,此模板才能正常工作。

更多关于Golang中{{range.}}为什么不起作用?的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


lutzhorn: 你期望得到什么样的HTML输出?

正中要害!

这正是我的第一个目标。谢谢!

Go Playground - The Go Programming Language

如果你想遍历JSON对象中的项目,可以这样做:

const templ = `<html><body>
{{ range $key, $value := . }}
   <li>{{ $key }}: {{ $value }}</li>
{{ end }}
</body></html>`

输出:

<html><body>
   <li>something: valueofa</li>
   <li>somethingElse: 1234</li>
</body></html>

参见 https://play.golang.org/p/lpRqZPmPsy1

lutzhorn:

如果你想遍历JSON对象中的项目,可以这样做:

不完全正确。但很接近。

这应该显示为一行

{“something”:“valueofa”, “somethingElse”: 1234}

而这应该显示为两行

{“something”:“valueofa”, “somethingElse”: 1234}, {“something”:“valueofb”, “somethingElse”: 3456}

我如何遍历一行或两行?有时数据只包含一行,所以我的代码应该能处理一条或多条记录。

Go Playground - The Go Programming Language

你期望得到什么样的HTML输出?

另外请注意

{"something":"valueofa", "somethingElse": 1234},
{"something":"valueofb", "somethingElse": 3456}

不是有效的JSON。你可以将这两个对象包装到一个JSON数组中:

[
  {"something":"valueofa", "somethingElse": 1234},
  {"something":"valueofb", "somethingElse": 3456}
]

你需要将

m := map[string]interface{}{}

改为

m := []map[string]interface{}{}
//   ^^ -- 数组!

并将模板改为

const templ = `<html><body>
{{ range . }}
   <li>{{ .something }}: {{ .somethingElse }}</li>
{{ end }}
</body></html>`

输出:

<html><body>
   <li>valueofa: 1234</li>
   <li>valueofb: 3456</li>
</body></html>

参见 https://play.golang.org/p/yoJIG42oRGT

{{range.}} 不起作用是因为你错误地使用了 range 动作。在 Go 模板中,{{range}} 用于迭代数组、切片、map 或 channel,但你的数据是 map 类型,而 {{range.}} 中的点号 . 代表当前上下文(整个 map),这会导致模板引擎尝试迭代 map 的键值对。

在你的代码中,{{range.}} 会迭代 map 的每个键值对,而每次迭代中的 . 会变成当前迭代的值(可能是字符串或数字)。当模板尝试执行 {{.something}} 时,实际上是在字符串或数字上查找 something 字段,这会导致错误。

以下是修正后的代码:

package main

import (
	"encoding/json"
	"html/template"
	"os"
)

func main() {
	t := template.Must(template.New("").Parse(templ))

	m := map[string]interface{}{}
	if err := json.Unmarshal([]byte(jsondata), &m); err != nil {
		panic(err)
	}

	if err := t.Execute(os.Stdout, m); err != nil {
		panic(err)
	}
}

const templ = `<html><body>
    {{.something}}
    {{.somethingElse}}
</body></html>`

const jsondata = `{"something":"valueofa", "somethingElse": 1234}`

如果你确实需要迭代 map 的键值对,可以这样写:

const templ = `<html><body>
    {{range $key, $value := .}}
        Key: {{$key}}, Value: {{$value}}
    {{end}}
</body></html>`

或者如果你有一个数组/切片需要迭代:

package main

import (
	"encoding/json"
	"html/template"
	"os"
)

func main() {
	t := template.Must(template.New("").Parse(templ))

	var data []map[string]interface{}
	if err := json.Unmarshal([]byte(jsondata), &data); err != nil {
		panic(err)
	}

	if err := t.Execute(os.Stdout, data); err != nil {
		panic(err)
	}
}

const templ = `<html><body>
    {{range .}}
        {{.something}}
        {{.somethingElse}}
    {{end}}
</body></html>`

const jsondata = `[
    {"something":"value1", "somethingElse": 1234},
    {"something":"value2", "somethingElse": 5678}
]`

在你的原始代码中,当没有 {{range.}} 时,点号 . 直接代表整个 map,所以 {{.something}} 能够正确访问 map 中的 “something” 键。

回到顶部