型エイリアス / 独自型
| 対応: | Go 1.9(2017) |
|---|
Goでは『type』キーワードで既存の型に名前を付けた独自型を定義できます。独自型にはメソッドを追加でき、型エイリアス(=)は元の型と完全に同一として扱われます。
構文
// 独自型を定義します(元の型とは別の型として扱われます)。
type 型名 既存の型
// 型エイリアスを定義します(元の型と完全に同一の型として扱われます)。
type 型名 = 既存の型
// 独自型にメソッドを追加します。
func (v 型名) メソッド名() 戻り値型 {
// 処理
}
独自型 vs 型エイリアス
| 定義方法 | 概要 |
|---|---|
| type MyType int | 独自型を定義します。元の型(int)とは別の型として扱われ、代入時に明示的な変換が必要です。 |
| type MyAlias = int | 型エイリアスを定義します。元の型(int)と完全に同じ型として扱われ、変換なしで相互代入できます。 |
| func (v MyType) M() | 独自型にメソッドを追加します。組み込み型(int, string など)に直接メソッドは追加できませんが、独自型にすることで可能になります。 |
| type 型名 struct{...} | 構造体の独自型を定義します。フィールドを持つ複合型を作成できます。 |
サンプルコード
sample_type_alias.go
package main
import "fmt"
// int型を基にした独自型を定義します。
type Celsius float64
type Fahrenheit float64
// Celsius型にメソッドを追加します。
func (c Celsius) ToFahrenheit() Fahrenheit {
return Fahrenheit(c*9/5 + 32)
}
func (c Celsius) String() string {
return fmt.Sprintf("%.1f°C", float64(c))
}
// string型を基にした独自型です。
type UserID string
func (id UserID) Prefix() string {
return "user_" + string(id)
}
// 型エイリアスの例です(= を使います)。
type Meter = float64 // float64と完全に同一の型として扱われます。
func main() {
// 独自型は元の型と区別されます。
boiling := Celsius(100)
fmt.Println(boiling) // 『100.0°C』と出力されます(Stringメソッドが呼ばれます)。
fmt.Println(boiling.ToFahrenheit())
// 独自型と元の型の間の代入には明示的な変換が必要です。
var raw float64 = 37.5
body := Celsius(raw) // float64からCelsiusへ変換します。
fmt.Println(body)
// UserIDの使い方です。
id := UserID("42")
fmt.Println(id.Prefix())
// 型エイリアスは元の型と完全に同一です。
var distance Meter = 100.0
var d float64 = distance // 変換なしで代入できます。
fmt.Println(d)
// 独自の型で列挙値(enum相当)を作ります。
type Direction int
const (
North Direction = iota
East
South
West
)
dir := North
fmt.Println(dir)
}
go run type_alias.go 100.0°C 212 37.5°C user_42 100 0
概要
独自型を使うと、同じ基底型でも意味の異なる値(例:摂氏と華氏、ユーザーIDと商品IDなど)を型レベルで区別できるため、誤った代入をコンパイル時に検出できます。
独自型と基底型の間の代入は明示的な型変換が必要です。型エイリアス(=)は元の型と同一のため変換不要ですが、メソッドを追加することはできません。
Goには列挙型(enum)がありませんが、独自型と『iota』を組み合わせることで同様の表現が可能です。独自型を定義する際は、そのパッケージ内での型安全性が向上します。
記事の間違いや著作権の侵害等ございましたらお手数ですがこちらまでご連絡頂ければ幸いです。