19

给定模板:

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

这可以输出:

one, two, three

但是,如果我想输出:

one, two, and three

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

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

是否可以检测模板范围内的最后一个值?干杯。

4

4 回答 4

20

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

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)
}

注意:您也可以不使用反射len功能(归功于 Russ Cox): http ://play.golang.org/p/V94BPN0uKD

参考

于 2014-03-13T10:02:26.043 回答
3

我们今天在 docker inspect 命令中使用格式时遇到了同样的问题。在不修补 Docker 的情况下获取最后一个元素的最简单方法是(为了便于阅读,表达式已分成几行):

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

所以在我们的例子中,我们需要没有注册地址和版本的镜像名称。例如,像registry.domain.local/images/nginx:latest这样的镜像名称变为nginx

PS:你需要 Go >= 1.11 才能完成这项工作(https://github.com/golang/go/issues/10608

PPS:这个问题是关于 Go 模板的,但是对于那些对 Docker 有同样问题的人来说,这里的配置示例:

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

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>
于 2019-02-14T14:16:56.020 回答
1

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

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

使用如下:

{{$lenMyList := len .MyList}}
{{range $index, $item := .MyList}}
    <div>
        {{.SomeItemProp}}
        {{if (isLast $index $lenMyList)}}
            Last Item
        {{end}}
    </div>
{{end}}
于 2021-08-16T22:06:39.973 回答
0

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

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

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}}and {{end}}{{$e}}{{end}}.`))
    a := []string{"one", "two", "three"}
    t.Execute(os.Stdout, a)
}
于 2021-12-06T10:02:50.010 回答