2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Go1.18からtext/templateのand, orが短絡評価されるようになった

Posted at

表題の通りです。

and, or の右辺値で副作用を起こすテンプレートを書いていた場合、Go1.17と1.18で挙動が変わります。Go本体と同じ仕様になったので分かりやすいですね。

テンプレート
{{$d := dict}}
{{or 1 (set $d "msg" "right value is evaluated!")}}
{{$d}}

go1.17: or の右辺値も評価されるので、 $d にキーが追加されている

go1.17

1
map[msg:right value is evaluated!]

go1.18: or の左辺値がtruthyなので短絡評価され、 $d にキーが追加されない

go1.18

1
map[]

挙動は何によって変わる?

Go本体のバージョンで決まります。 go.mod ファイルのGoディレクティブは関係ありませんでした1

そのため、go install で同じバージョンのバイナリを落としてきても、Go本体のバージョンによって挙動が変わります。

go1.18
$ go version
go version go1.18 linux/amd64
$ echo | go run github.com/syuparn/tmplscript@v0.6.0 '{{$d := dict}}{{$_ := or 1 (set $d "msg" "right value is evaluated!")}}{{$d}}'
map[]
go1.17
$ go version
go version go1.17.6 linux/amd64
$  echo | go run github.com/syuparn/tmplscript@v0.6.0 '{{$d := dict}}{{$_ := or 1 (set $d "msg" "right value is evaluated!")}}{{$d}}'
map[msg:right value is evaluated!]

(kubectlhelm 等、ビルドに使ったGoのバージョン情報も表示するツールはこのような挙動の違いを意識しているのでしょうか?)

とはいえ、Goは標準パッケージ含めv1系の後方互換を保証しているので、実装の穴をついて変なことをしない限りバージョンを意識する必要は無さそうです2

おわりに

変な挙動やバグに依存したコードは書かないようにしよう! :innocent:

  1. 公式リファレンスでは「ディレクティブより新しいバージョンの言語仕様が使われたらコンパイルエラーにする」と書かれていますが、標準パッケージについての記述はありませんでした。また、標準パッケージは go.mod でもバージョン管理されないので、純粋に本体バージョンに紐づくと考えてよさそうです。

  2. 短絡評価が非互換の変更に当たるかどうかはissueでも長い間議論されていたようです。最終的に、右辺値を評価することはgodocに仕様として書かれていないので、nil pointer dereferenceを回避できる利点のほうが大きいと判断され採用されました。

2
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?