模板范围中的最后一项

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

Last item in a template range

问题

给定模板:

{{range $i, $e := .SomeField}}
        {{if $i}}, {{end}}
        $e.TheString
{{end}}

这可以输出:

one, two, three

然而,如果我想输出:

one, two, and three

我需要知道上述范围中的最后一个元素。

我可以设置一个变量来保存数组.SomeField的长度,但它将始终为3,并且上面的$i值只能达到2。根据我所见,模板中不能进行算术运算。

在模板范围中检测最后一个值是否可能?谢谢。

英文:

Given the template:

{{range $i, $e := .SomeField}}
        {{if $i}}, {{end}}
        $e.TheString
{{end}}

This can output:

one, two, three

If, however, I want to output:

one, two, and three

I'd need to know which is the last element in the range above.

I can set a variable that holds the length of the array .SomeField, but that will always be 3, and the $i value above will only ever get to 2. And you can't perform arithmetic in templates from what I've seen.

Is detecting the last value in a template range possible? Cheers.

答案1

得分: 21

这可能不是最优雅的解决方案,但是这是我能找到的最好的解决方案:

package main

import (
    "os"
    "reflect"
    "text/template"
)

var fns = template.FuncMap{
    "last": func(x int, a interface{}) bool {
        return x == reflect.ValueOf(a).Len() - 1
    },
}

func main() {
    t := template.Must(template.New("abc").Funcs(fns).Parse(`{{range  $i, $e := .}}{{if $i}}, {{end}}{{if last $i $}}and {{end}}{{$e}}{{end}}.`))
    a := []string{"one", "two", "three"}
    t.Execute(os.Stdout, a)
}

**注意:**你也可以使用len函数而不使用反射来实现(感谢Russ Cox):
http://play.golang.org/p/V94BPN0uKD

参考资料:

英文:

This is probably not the most elegant solution but it's the best I could find:

http://play.golang.org/p/MT91mLqk1s

package main

import (
    "os"
    "reflect"
    "text/template"
)

var fns = template.FuncMap{
    "last": func(x int, a interface{}) bool {
        return x == reflect.ValueOf(a).Len() - 1
    },
}


func main() {
    t := template.Must(template.New("abc").Funcs(fns).Parse(`{{range  $i, $e := .}}{{if $i}}, {{end}}{{if last $i $}}and {{end}}{{$e}}{{end}}.`))
    a := []string{"one", "two", "three"}
    t.Execute(os.Stdout, a)
}

Note: You can also do it without reflect using the len function (credit to Russ Cox):
http://play.golang.org/p/V94BPN0uKD

c.f.

答案2

得分: 4

今天在使用docker inspect命令中处理格式时,我们遇到了同样的问题。
在不修改Docker的情况下,最简单的方法是(为了便于阅读,将表达式拆分成了多行):

{{ $image := "" }}
{{ range split .ContainerImageName "/" }}
    {{ $image = . }}{{ end }}
{{ index (split $image ":") 0 }}

所以在我们的情况下,我们需要获取不带注册表地址和版本的镜像名称。
例如,像registry.domain.local/images/nginx:latest这样的镜像名称将变为nginx

附注:您需要Go >= 1.11来完成此任务(https://github.com/golang/go/issues/10608)。

附注:问题是关于Go模板的,但对于那些在Docker中遇到相同问题的人,这里有一些配置示例:

1)在daemon.json中使用Go模板

cat /etc/docker/daemon.json

{
    "log-driver": "syslog",
    "log-opts": {
        "syslog-address": "udp://127.0.0.1:20627",
        "tag": "{{ $image :=  \"\" }}{{ range split .ContainerImageName \"/\" }}{{ $image = . }}{{ end }}{{ index (split $image \":\") 0 }}/{{.Name}}"
}

2)使用-f选项的Go模板:

docker inspect \
  -f '{{ $image := "" }}{{ range split .Config.Image "/" }}{{ $image = . }}{{ end }}{{ index (split $image ":") 0 }}' \
  <container>
英文:

We had same problem today when working with format in docker inspect command.
The easiest way to get the last element without patching Docker was (the expression has been split into lines for ease of reading):

{{ $image := &quot;&quot; }}
{{ range split .ContainerImageName &quot;/&quot; }}
    {{ $image = . }}{{ end }}
{{ index (split $image &quot;:&quot;) 0 }}

So in our case, we needed the image name without registry address and version.
For example, image name like registry.domain.local/images/nginx:latest becomes nginx.

P.S: You need Go >= 1.11 to do the job (https://github.com/golang/go/issues/10608)

P.P.S: The question was about Go template but for those who had same problems with Docker here the configuration examples:

  1. Using Go template in daemon.json

cat /etc/docker/daemon.json

{
    &quot;log-driver&quot;: &quot;syslog&quot;,
    &quot;log-opts&quot;: {
        &quot;syslog-address&quot;: &quot;udp://127.0.0.1:20627&quot;,
        &quot;tag&quot;: &quot;{{ $image :=  \&quot;\&quot; }}{{ range split .ContainerImageName \&quot;/\&quot; }}{{ $image = . }}{{ end }}{{ index (split $image \&quot;:\&quot;) 0 }}/{{.Name}}&quot;
}
  1. Using Go template with -f option:
docker inspect \
  -f &#39;{{ $image := &quot;&quot; }}{{ range split .Config.Image &quot;/&quot; }}{{ $image = . }}{{ end }}{{ index (split $image &quot;:&quot;) 0 }}&#39; \
  &lt;container&gt;

答案3

得分: 1

我遇到了这个问题,并通过添加一个isLast辅助函数来解决它。它需要在辅助函数外计算长度,但阅读起来更容易一些。

var helpers template.FuncMap = map[string]interface{}{
	"isLast": func(index int, length int) bool {
		return index+1 == length
	},
}

使用方法如下:

{{$lenMyList := len .MyList}}
{{range $index, $item := .MyList}}
	<div>
		{{$item.SomeItemProp}}
		{{if (isLast $index $lenMyList)}}
			最后一项
		{{end}}
	</div>
{{end}}
英文:

I ran into this and solved it by adding an isLast helper function. It does require computing the length outside the helper, but it's a bit easier to read.

var helpers template.FuncMap = map[string]interface{}{
	&quot;isLast&quot;: func(index int, len int) bool {
		return index+1 == len
	},
}

Which is used like:

{{$lenMyList := len .MyList}}
{{range $index, $item := .MyList}}
	&lt;div&gt;
		{{.SomeItemProp}}
		{{if (isLast $index $lenMyList)}}
			Last Item
		{{end}}
	&lt;/div&gt;
{{end}}

答案4

得分: 1

稍微更优雅的解决方案,避免在每次迭代中调用lensub/add

package main

import (
	"os"
	"text/template"
)

var fns = template.FuncMap{
	"eq": func(x, y interface{}) bool {
		return x == y
	},
	"sub": func(y, x int) int {
		return x - y
	},
}

func main() {
	t := template.Must(template.New("abc").Funcs(fns).Parse(`{{$last := (len . | sub 1)}}{{range  $i, $e := .}}{{if $i}}, {{end}}{{if eq $i $last}}{{end}}{{$e}}{{end}}。`))
	a := []string{"one", "two", "three"}
	t.Execute(os.Stdout, a)
}

链接:https://go.dev/play/p/oRznNPw-YCr

英文:

Slightly more elegant solution, avoids calling len or sub/add on every iteration:

https://go.dev/play/p/oRznNPw-YCr

package main

import (
	&quot;os&quot;
	&quot;text/template&quot;
)

var fns = template.FuncMap{
	&quot;eq&quot;: func(x, y interface{}) bool {
		return x == y
	},
	&quot;sub&quot;: func(y, x int) int {
		return x - y
	},
}

func main() {
	t := template.Must(template.New(&quot;abc&quot;).Funcs(fns).Parse(`{{$last := (len . | sub 1)}}{{range  $i, $e := .}}{{if $i}}, {{end}}{{if eq $i $last}}and {{end}}{{$e}}{{end}}.`))
	a := []string{&quot;one&quot;, &quot;two&quot;, &quot;three&quot;}
	t.Execute(os.Stdout, a)
}

huangapple
  • 本文由 发表于 2014年3月13日 09:26:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/22367337.html
匿名

发表评论

匿名网友

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

确定