型エイリアスは Go 1.9 で追加された新機能で、主にコードのアップグレードや移行における型の互換性の問題を解決するために使用されます。 C/ C++言語では、コードのリファクタリングとアップグレードでマクロを使用して新しいコードをすばやく定義できますが、Go 言語ではマクロを追加するオプションはありませんが、リファクタリングで最も厄介な型名の変更の問題は解決されます。
Go 1.9 より前の組み込み型を定義するコードは次のように書かれていました。
type byte uint8
type rune int32
Go 1.9 以降のバージョンは次のようになります。
type byte = uint8
type rune = int32
この変更は、タイプ エイリアスを使用して行われた変更です。
型の別名と型定義を区別する
型の別名を定義する方法は次のとおりです。
type TypeAlias = Type
型エイリアスのルール: TypeAlias は Type の単なるエイリアスです。本質的に、TypeAlias と Type は同じ型です。子供の頃にペット名と赤ちゃんの名前を持ち、その後学名を使用するのと同じです。学校に行くと、英語の先生が彼に英語の名前を付けてくれるでしょう。
型エイリアスと型定義には等号の違いがあるだけのように見えますが、実際にはどのような違いがあるのでしょうか?以下は理解すべきコードの一部です。
package main
import(
"fmt"
)
// NewIntをint型と定義する
type NewInt int
// intをIntAliasという別名にする
type IntAlias = int
func main() {
// aをNewInt型として宣言する
var a NewInt
// aの型名を確認する
fmt.Printf("a type: %T\n", a)
// a2をIntAlias型として宣言する
var a2 IntAlias
// a2の型名を確認する
fmt.Printf("a2 type: %T\n", a2)
}
コードを実行した結果:
a type: main.NewInt
a2 type: int
コードの説明は次のとおりです。
- 8 行目では、NewInt を int 型として定義しています。これは、型を定義する一般的な方法です。type キーワードの定義により、NewInt は新しい型を形成しますが、NewInt 自体は int 型の特性を保持しています。
- 11行目は、IntAliasをintと等価になるように使用して、IntAliasをintのエイリアスとして設定します。
- 16行目でaをNewInt型として宣言しており、この時点で出力するとaの値は0になります。
- 18 行目では、
%T
形式パラメータを使用して、変数 a 自体の型を出力します。 - 21行目でa2をIntAlias型として宣言しており、このときa2の値は0として出力されます。
- 23 行目、a2 変数の型を出力します。
結果は、a の型が main.NewInt であることを示します。これは、メイン パッケージで定義された NewInt 型を意味します。a2 の型は int、IntAlias 型はコード内にのみ存在し、IntAlias は存在しません。コンパイルが完了したら、タイプを入力します。
非ローカル型ではメソッドを定義できません
さまざまな型に自由に名前を付けることができるということは、独自のパッケージでこれらの型にメソッドを追加できるということですか?以下のコードデモをご覧ください。
package main
import(
"time"
)
// time.Durationの別名MyDurationを定義
type MyDuration = time.Duration
// MyDurationに関数を追加する
func(m MyDuration)EasySet(a string){
}
func main(){
}
コードの説明は次のとおりです。
- 8 行目では、time.Duration に MyDuration という名前の型エイリアスを設定します。
- 11 行目に、このエイリアスのメソッドを追加します。
上記のコードをコンパイルしてエラーを報告すると、情報は次のとおりです。
cannot define new methods on non-local type time.Duration
コンパイラーのヒント: 非ローカル型 time.Duration では新しいメソッドを定義できません。非ローカル型は time.Duration を参照します。メイン パッケージでは定義されていませんが、time パッケージで定義されており、これは time.Duration と同じではありません。メイン パッケージ。パッケージなので、パッケージに含まれていない型に対してメソッドを定義することはできません。
この問題を解決するには 2 つの方法があります。
- 8 行目を MyDuration time.Duration と入力するように変更します。つまり、MyDuration をエイリアスから型に変更します。
- MyDuration のエイリアス定義を time パッケージに入れます。
型エイリアスが構造体のメンバーとして埋め込まれている場合はどうなりますか?以下のコードを参照してください。
package main
import (
"fmt"
"reflect"
)
// Brand構造体を定義
type Brand struct {
}
// Brand構造体にShow()メソッドを追加
func (t Brand) Show() {
}
// Brandに別名FakeBrandを定義
type FakeBrand = Brand
// Vehicle構造体を定義
type Vehicle struct {
// 2つの構造体を埋め込む
FakeBrand
Brand
}
func main() {
// 変数aをVehicle型として宣言
var a Vehicle
// FakeBrandのShowを呼び出すように指定
a.FakeBrand.Show()
// aの反射型オブジェクトを取得
ta := reflect.TypeOf(a)
// aのすべてのメンバーを反復処理
for i := 0; i<ta.NumField(); i++ {
// aのメンバー情報
f := ta.Field(i)
// メンバーのフィールド名と型を出力する
fmt.Printf("FieldName: %v, FieldType: %v\n", f.Name, f.Type.
Name())
}
}
コード出力は次のとおりです。
FieldName: FakeBrand, FieldType: Brand
FieldName: Brand, FieldType: Brand
コードの説明は次のとおりです。
- 9 行目は商標の構造を定義します。
- 13 行目で、Show() メソッドをロゴ構造に追加します。
- 17 行目では、Brand のエイリアス FakeBrand を定義しています。
- 行 20 ~ 25 は車両構造 Vehicle を定義し、FakeBrand 構造と Brand 構造を埋め込みます。
- 30 行目で、Vehicle が としてインスタンス化されます。
- 33 行目で、Vehicle の FakeBrand の Show() メソッドを明示的に呼び出します。
- 36 行目では、reflection を使用して変数 a のリフレクション型オブジェクトを取得し、そのメンバーの型を確認します。
- 行 39 ~ 42 は、a の構造メンバーを調べます。
- 行 45、Vehicle タイプのすべてのメンバーの情報を出力します。
この例では、FakeBrand は Brand のエイリアスです。Vehicle に FakeBrand と Brand を埋め込むことは、2 つのブランドを埋め込むことを意味しません。FakeBrand のタイプは、名前の形式で Vehicle のメンバーに予約されます。
33 行目を次のように変更してみると、
a.Show()
コンパイラはエラーを報告します。
ambiguous selector a.Show
Show() メソッドを呼び出す場合、両方の型に Show() メソッドがあるため、あいまいさが発生し、FakeBrand の本質が確かに Brand 型であることが証明されます。