Go 1.9 と Type Alias

遅ればせながらの記事で申し訳ないが Go 1.9 がリリースされた。

詳しい内容はリリースノートを見ていただくとして,今回の目玉は type alias 機能だろう。

まず type キーワードを使った簡単な足し算を書いてみる。

package main

import (
    "fmt"
)

type Num1 int

func (n1 Num1) Add(n2 Num1) Num1 {
    return n1 + n2
}

func main() {
    n1 := Num1(1)
    n2 := Num1(2)
    fmt.Println(n1.Add(n2))
}

実行結果は 3 と出力されるはずである。 ここで “type Num2 Num1” と記述を追加し,この型を使って足し算を行ってみる。

package main

import (
    "fmt"
)

type Num1 int

func (n1 Num1) Add(n2 Num1) Num1 {
    return n1 + n2
}

type Num2 Num1

func main() {
    n1 := Num2(1)
    n2 := Num2(2)
    fmt.Println(n1.Add(n2))
}

これを実行しようとすると

n1.Add undefined (type Num2 has no field or method Add)

とコンパイルエラーになる。 何故か。 Num1Num2 は異なる型だからだ。 型 Num1 に紐付いている関数 Add() は,型 Num2 には紐付かない。 継承されないわけだ(Num1 へキャストはできる)。

では今度は “type Num2 = Num1” と記述を変更してみる。

package main

import (
    "fmt"
)

type Num1 int

func (n1 Num1) Add(n2 Num1) Num1 {
    return n1 + n2
}

type Num2 = Num1

func main() {
    n1 := Num2(1)
    n2 := Num2(2)
    fmt.Println(n1.Add(n2))
}

今度はコンパイルエラーにならず 3 と出力される。 この “type Num2 = Num1” という構文が type alias を指し,この記述によって Num1Num2全く同じ型 として扱われる1

なんでこんな妙ちきりんな言語仕様が追加されたかというと,実はこれ,リファクタリングの為に設けられたのである。

Go now supports type aliases to support gradual code repair while moving a type between packages. The type alias design document and an article on refactoring cover the problem in detail.
via Go 1.9 Release Notes

もともと Go 言語はリファクタリングを厚遇する言語と言える。 たとえば duck typing などはその最たる例だろう。

まぁ,あまり積極的に使う機能ではないかもしれないが,こういうこともできると覚えておくといいだろう。

ブックマーク

参考図書

photo
Java言語で学ぶリファクタリング入門
結城 浩
SBクリエイティブ 2007-01-26
評価

増補改訂版 Java言語で学ぶデザインパターン入門 増補改訂版 Java言語で学ぶデザインパターン入門 マルチスレッド編 数学ガールの秘密ノート/積分を見つめて プログラマの数学 Java言語プログラミングレッスン 第3版(下) オブジェクト指向を始めよう JavaScript関数型プログラミング 複雑性を抑える発想と実践法を学ぶ impress top gearシリーズ プリンシプル オブ プログラミング 3年目までに身につけたい 一生役立つ101の原理原則 Java言語プログラミングレッスン 第3版(上) Java言語を始めよう 実践Javaコーディング作法 数学ガールの秘密ノート/微分を追いかけて

結城浩さんによる「リファクタリング本」。意外に Java 以外でも使える優れもの。

reviewed by Spiegel on 2017-09-14 (powered by G-Tools)


  1. 全く同じ型なので継承関係はなく,別名定義した型に独自に関数を紐付けることはできない。ちなみに別パッケージの型に対しても別名定義が可能である: type Time = time.Time [return]