迭代Go地图获取索引

huangapple go评论83阅读模式
英文:

Iterate Go map get index

问题

为了在模板中使用reveleven关键字,我想在使用range迭代时获取映射条目的索引。有没有办法做到这一点?
我的映射结构如下:

map[string][]string
英文:

In order to use revel's even keyword in templates I would like to get the index of a map entry when iterating with range. Is there any way to do so?
My map has the structure:

map[string][]string

答案1

得分: 14

在遍历map时实现索引的简单方法:

package main

import (
	"fmt"
)

func main() {
	mm := map[string]int{"xx": 1, "gg": 2}
	cnt := 0
	for a, b := range mm {
		fmt.Println("a", a, "b", b, "c", cnt)
		cnt++
	}
	fmt.Println("Hello, playground")
}

并打印输出:

a xx b 1 c 0
a gg b 2 c 1
Hello, playground
英文:

A Simple way to achieve index while looping through a map:

package main

import (
    "fmt"
)

func main() {
    mm := map[string]int{"xx" : 1, "gg" : 2}
    cnt := 0
    for a, b:= range mm{
    	fmt.Println("a", a, "b",b, "c" , cnt)
	    cnt++
    }
    fmt.Println("Hello, playground")
}

And prints:

a xx b 1 c 0
a gg b 2 c 1
Hello, playground

答案2

得分: 3

你可以通过注册一个提供必要帮助的函数来实现,而不能仅仅使用模板操作。

你可以注册一个返回函数(闭包)的函数,该函数在每次调用时交替返回其值(就像“奇数”和“偶数”索引交替一样):

func isEven() func() bool {
    e := false
    return func() bool {
        e = !e
        return e
    }
}

我将其命名为isEven(),以避免与raveleven()冲突。使用它:

func main() {
    t := template.Must(template.New("").Funcs(template.FuncMap{
        "isEven": isEven,
    }).Parse(templ))

    m := map[string]string{
        "a": "A", "b": "B", "c": "C", "d": "D",
    }
    if err := t.Execute(os.Stdout, m); err != nil {
        panic(err)
    }
}

const templ = `{{$e := isEven}}
{{- range $k, $v := . -}}
    [even:{{call $e}}] key={{$k}}; value={{$v}}
{{end}}`

输出结果(在Go Playground上尝试):

[even:true] key=a; value=A
[even:false] key=b; value=B
[even:true] key=c; value=C
[even:false] key=d; value=D

如果你想在奇数和偶数迭代中获得不同的输出,你可以在{{if}}操作中调用$e,像这样:

const templ = `{{$e := isEven}}
{{- range $k, $v := . -}}
    [{{if call $e}}even{{else}}odd {{end}}] key={{$k}}; value={{$v}}
{{end}}`

这种情况下的输出结果(在Go Playground上尝试):

[even] key=a; value=A
[odd ] key=b; value=B
[even] key=c; value=C
[odd ] key=d; value=D

内部原理

这个模板操作:

{{$e := isEven}}

创建一个名为$e的新模板变量,其值将是isEven()函数调用的结果(返回值)。isEven()返回一个函数值,即一个闭包,它可以访问类型为bool的局部变量e。当你执行{{call $e}}时,你调用的不是isEven() Go函数,而是它返回的函数(闭包),并且存储在$e中。该闭包引用了局部bool变量e,它在isEven()返回的函数可访问之前不会被“释放”。

因此,每当你执行{{call $e}}时,它调用闭包,该闭包“拥有”一个类型为boole变量,其值在对$e的多次调用之间保持不变。

如果你在模板中再次调用isEven,那么它将返回一个新的函数(闭包),封装了一个新的局部变量e的实例,与第一个isEven()调用返回的闭包的封装变量是独立的。

英文:

You can't do this only with template actions, but you may register a function which provides the necessary help.

You may register a function which returns a function (closure), which alternates its return value whenever called (exactly how "odd" and "even" indices alternate):

func isEven() func() bool {
	e := false
	return func() bool {
		e = !e
		return e
	}
}

I named it isEven() to not collide with ravel's even(). Using it:

func main() {
	t := template.Must(template.New("").Funcs(template.FuncMap{
		"isEven": isEven,
	}).Parse(templ))

	m := map[string]string{
		"a": "A", "b": "B", "c": "C", "d": "D",
	}
	if err := t.Execute(os.Stdout, m); err != nil {
		panic(err)
	}
}

const templ = `{{$e := isEven}}
{{- range $k, $v := . -}}
    [even:{{call $e}}] key={{$k}}; value={{$v}}
{{end}}`

Output (try it on the Go Playground):

[even:true] key=a; value=A
[even:false] key=b; value=B
[even:true] key=c; value=C
[even:false] key=d; value=D

If you want different output for odd and even iterations, you can call $e in an {{if}} action, like this:

const templ = `{{$e := isEven}}
{{- range $k, $v := . -}}
    [{{if call $e}}even{{else}}odd {{end}}] key={{$k}}; value={{$v}}
{{end}}`

Output of this (try it on the Go Playground):

[even] key=a; value=A
[odd ] key=b; value=B
[even] key=c; value=C
[odd ] key=d; value=D

Under the hood

This template action:

{{$e := isEven}}

Creates a new template variable named $e, and its value will be the result (return value) of the isEven() function call. isEven() returns a function value, a closure that has access to a local variable e of type bool. When later you do {{call $e}}, you're not calling the isEven() Go function, but the function it returned (the closure) and is stored in $e. That closure has a reference to the local bool variable e, it is not "freed" until the function returned by isEvent() is accessible.

So whenever you do {{call $e}}, it calls the closure, which "has" an e variable of type bool, whose value is retained between calls of this $e.

If you would call isEvent in the template again, that would return a new function (closure), wrapping a new instance of the local variable e, being independent of the first wrapped variable of the closure returned by the first isEvent() call.

答案3

得分: 1

在Go语言中,映射(Map)条目没有索引;你无法从任何元素中获取索引。此外,每次使用range迭代映射时,得到的顺序都是不同的,这是另一个暗示映射中没有索引概念的线索。

索引只与有序的数据结构相关(例如数组、切片、列表等),而不是映射。请查看https://blog.golang.org/go-maps-in-action了解更多详细信息。

英文:

Map entries have no index in Go; there's no way you can get an index out of any element. Also, each time you iterate on a map with range, you get a different order - another hint that there's no index concept in maps.

Indexes are related to ordered data structures only (e.g. arrays, slices, lists, etc), not maps. Take a look at https://blog.golang.org/go-maps-in-action for more details.

答案4

得分: -2

你好!以下是要翻译的内容:

{{range $key, $element := .Map}}
{{$index := index .Map $key}}
{{end}}

英文:
{{range $key, $element := .Map}}
  {{$index := index .Map $key}}
{{end}}

huangapple
  • 本文由 发表于 2017年3月22日 18:12:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/42948556.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定