2021/09/24

Recent entries from same category

  1. Go 言語プログラミングエッセンスという本を書きました。
  2. errors.Join が入った。
  3. unsafe.StringData、unsafe.String、unsafe.SliceData が入った。
  4. Re: Go言語で画像ファイルか確認してみる
  5. net/url に JoinPath が入った。

Go のテンプレートエンジンは、一般的なテンプレートエンジンの記法と気色が異なり、独特の文法で記述するのですが、ループ制御構文に関してはお世辞にも満足できる物ではありませんでした。それは continue や break が無いというのが理由です。continue や break が無かったので、無駄に if をネストして条件にあった値を出力しなければならず、必然的に無駄な if のネストが起きていました。

■ビーフストロガノフ
  2011年 受賞
  2019年 受賞
■カレーライス
  2012年 受賞
■満漢全席
  2015年 受賞
  2019年 受賞

例えば上記の様な出力をするには、以下の様なテンプレートを書かなければなりませんでした。

package main

import (
    "os"
    "text/template"
)

var tmpl = `
{{- range .}}
{{- if gt .Value 3 -}}
■{{.Name}}
{{- range .Years }}
  {{ . -}}年 受賞
{{- end}}
{{end -}}
{{- end -}}
`

type Foo struct {
    Name  string
    Value int
    Years []int
}

func main() {
    tpl := template.Must(template.New("").Parse(tmpl))
    tpl.Execute(os.Stdout, []Foo{
        {Name: "ぶどう", Value: 1, Years: []int{201120142019}},
        {Name: "みかん", Value: 2, Years: []int{2011}},
        {Name: "ぎょうざ", Value: 3, Years: []int{2020}},
        {Name: "ビーフストロガノフ", Value: 4, Years: []int{20112019}},
        {Name: "カレーライス", Value: 5, Years: []int{2012}},
        {Name: "満漢全席", Value: 6, Years: []int{20152019}},
    })
}
html/template, text/template: implement break and continue for range … · golang/go@d0dd26a · GitHub

…loops Break and continue for range loops was accepted as a proposal in June 2017. It was implemente...

https://github.com/golang/go/commit/d0dd26a88c019d54f22463daae81e785f5867565

continue を使える様になった事で、ループのネストが下げられる様になりました。

package main

import (
    "os"
    "text/template"
)

var tmpl = `
{{- range .}}
{{- if le .Value 3 -}}{{continue}}{{end -}}
■{{.Name}}
{{- range .Years }}
  {{ . -}}年 受賞
{{- end}}
{{end -}}
`

type Foo struct {
    Name  string
    Value int
    Years []int
}

func main() {
    tpl := template.Must(template.New("").Parse(tmpl))
    tpl.Execute(os.Stdout, []Foo{
        {Name: "ぶどう", Value: 1, Years: []int{201120142019}},
        {Name: "みかん", Value: 2, Years: []int{2011}},
        {Name: "ぎょうざ", Value: 3, Years: []int{2020}},
        {Name: "ビーフストロガノフ", Value: 4, Years: []int{20112019}},
        {Name: "カレーライス", Value: 5, Years: []int{2012}},
        {Name: "満漢全席", Value: 6, Years: []int{20152019}},
    })
}

サンプルが単純な物なので効果が伝わりにくいですが、テンプレートを書く手間が少し楽になった気がします。また break が入った事で if にマッチしない部分が無駄にループを回す事もなくなったので、Go 側から巨大な配列を事前にカットして渡す必要も無くなる事になります。

Posted at by