2016/06/03

golangのテンプレート内でメソッドを呼び出す

text/template のサンプルをいくつか見てみたところ、構造体を渡してフィールドを埋め込んで表示するサンプルばかりだった。じゃあメソッド呼べるの?と思ったので試してみた。

package main
import (
"os"
"text/template"
)
type Person struct {
Name string
City string
}
func (p Person) GetAge() int {
return 36
}
func main() {
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge()}}) lives in {{.City}}.")
if err != nil {
panic(err)
}
p := Person{"pinzolo", "Kyoto"}
err = tmpl.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}
panic: template: test:1: unexpected "(" in operand

goroutine 1 [running]:
panic(0x13f660, 0xc82000a440)
 /usr/local/Cellar/go/1.6.2/libexec/src/runtime/panic.go:481 +0x3e6
main.main()
 /Users/pinzolo/.cache/junkfile/2016/06/2016-06-03-101728.go:20 +0x24b
exit status 2
できなかった。

括弧が unexpected なら、括弧なしならどうなの??

package main
import (
"os"
"text/template"
)
type Person struct {
Name string
City string
}
func (p Person) GetAge() int {
return 36
}
func main() {
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}.")
if err != nil {
panic(err)
}
p := Person{"pinzolo", "Kyoto"}
err = tmpl.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}
pinzolo(36) lives in Kyoto.
出来た。正直言って予想外だった。

じゃあ、引数はどうやって渡すの?lenとかのビルトイン関使うようにスペース開ければいいかな?

package main
import (
"os"
"text/template"
)
type Person struct {
Name string
City string
}
func (p Person) GetAge() int {
return 36
}
func (p Person) GetFutureAge(yearAfter int) int {
return p.GetAge() + yearAfter
}
func main() {
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}. 2 years later he is {{.GetFutureAge 2}}.")
if err != nil {
panic(err)
}
p := Person{"pinzolo", "Kyoto"}
err = tmpl.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}
pinzolo(36) lives in Kyoto. 2 years later he is 38.
出来た。

じゃあ2つ以上の引数はスペース区切りかな?

package main
import (
"os"
"text/template"
)
type Person struct {
Name string
City string
}
func (p Person) GetAge() int {
return 36
}
func (p Person) GetFutureAge(yearAfter int, other int) int {
return p.GetAge() + yearAfter + other
}
func main() {
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}. 5 years later he is {{.GetFutureAge 2 3}}.")
if err != nil {
panic(err)
}
p := Person{"pinzolo", "Kyoto"}
err = tmpl.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}
pinzolo(36) lives in Kyoto. 5 years later he is 41.
やっぱり。

趣向を変えて、構造体のポインタを渡してもうまく動くかな?

package main
import (
"os"
"text/template"
)
type Person struct {
Name string
City string
}
func (p *Person) GetAge() int {
return 36
}
func (p *Person) GetFutureAge(yearAfter int) int {
return p.GetAge() + yearAfter
}
func main() {
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}. 2 years later he is {{.GetFutureAge 2}}.")
if err != nil {
panic(err)
}
p := &Person{"pinzolo", "Kyoto"}
err = tmpl.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}
package main
import (
"os"
"text/template"
)
type Person struct {
Name string
City string
}
func (p Person) GetAge() int {
return 36
}
func (p Person) GetFutureAge(yearAfter int) int {
return p.GetAge() + yearAfter
}
func main() {
tmpl, err := template.New("test").Parse("{{.Name}}({{.GetAge}}) lives in {{.City}}. 2 years later he is {{.GetFutureAge 2}}.")
if err != nil {
panic(err)
}
p := &Person{"pinzolo", "Kyoto"}
err = tmpl.Execute(os.Stdout, p)
if err != nil {
panic(err)
}
}
pinzolo(36) lives in Kyoto. 2 years later he is 38.
問題ない。構造体に定義したメソッドもポインタに定義したメソッドも呼び出せてる。

結構色々出来るんだな text/template

2016/06/01

comment on exported function GetXxx should be of thee form "GetXxx ..."

Go は大文字で始まる public な型・関数に対してその直前に書かれたコメントをドキュメントとして扱ってくれる。
lintでドキュメント書くように勧めてくるのは意識高い感じでよい。
ただ、面倒なことにその型なり関数なりの名前で始まるのを推奨しているらしく、そうじゃない場合タイトルのような警告を出してくる。

こんな感じ

package main
// 設定情報を格納する ← メッセージ出しやがる
type Config struct {}
// ConfigError は設定情報に不備があった場合のエラー情報を格納する ← 推奨しているらしい
type ConfigError struct {}
// Fooを返す ← メッセージ出しやがる
func GetFoo() string {
return "Foo"
}
// GetBar は Bar を返す ← 推奨しているらしい
func GetBar() string {
return "Bar"
}

英語で書く場合なら、GetFoo returns Foo みたいに書きやすいのだが、日本語でコメントを書く場合冗長なコメントになりがちな気がする。
関数名も型名も真下にあるじゃないか!
なんて言っても仕方ないし、エディタにマークつけ続けられるのも気持ち悪いのでせっせとおっしゃる通りにするのだ