APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

Golangの独自型を使い引数の順番ミスを減らす

先進サービス開発事業部の山岡です。

Golangには他のプログラミング言語と同様関数があり、これに引数として値を渡すことで見通し良く様々な機能を作ることができます。しかし関数に複数の引数を渡す場合、時折順番間違いが問題となることがあります。

例えば以下のようなコードであると、1番目・2番目共に関数の型が同じであるため順番を間違えてもビルドエラーにはなりません。アプリケーション側で表示がおかしくなったりエラーが発生するくらいならまだマシで、場合によってはDBの内容に問題が起こり面倒な事態に陥ることもあり得ます。

func main() {
    name := "山田ゴーファー"
    description := "私はGopherです"
    PrintProfile(description, name)
}

func PrintProfile(name, description string) {
    fmt.Printf("Name: %s\nDescription: %s", name, description)
}
$ go run iamgopher.go
Name: 私はGopherです
Description: 山田ゴーファー

独自型を使って回避

Golangは下記のような書式で独自型を定義する機能があるので、これを使い個別に新たな型を作ることで万一順番を間違った場合にビルドエラーを起こすことができます。この状態であればうっかりミスは防げますし、リファクタリング時の安全性向上にも寄与できることでしょう。

type (
    MyName string
    MyDescription string
)

func main() {
    name := MyName("山田ゴーファー")
    description := MyDescription("私はGopherです")
    PrintProfile(description, name)
}

func PrintProfile(name MyName, description MyDescription) {
    fmt.Printf("Name: %s\nDescription: %s", name, description)
}
$ go run iamgopher.go
iamgopher.go:15:14: cannot use description (type MyDescription) as type MyName in argument to PrintProfile
iamgopher.go:15:14: cannot use name (type MyName) as type MyDescription in argument to PrintProfile

型エイリアスとは別です

似ている機能として、Golang1.9からは型宣言時に型名同士の間に = を書くことで型エイリアスを作ることができます。しかしこれはあくまで同一な型の別名でありコンパイル時にも同じ型として扱われるため今回の目的には合いません。

type (
    MyName = string
    MyDescription = string
)