Go言語 ~基礎編~ Defined Type

go

今回は、Type宣言について深掘りしていきます。

学習記事まとめ

Defined Type

Go言語には、int, float64, string, boolなどの基本typeが存在しますが、自分で定義することも可能です。ここでは、Defined Typeと呼ぶことにしましょう。

KOUKI
KOUKI

Defined Type? 何それ??て感じだと思うので、まずはサンプルをお見せします。

「Liters」と「Gallons」をDefined Typeとして宣言しました。

これで、変数宣言時にintやstringと同じ感覚で使用可能になります。

ただし、LitersとGallonsは別々のtypeになっているので、それぞれを入れ替えて使用することはできません。

宣言したtypeと格納した値のtypeが異なるため、エラーになりました。ただし、型変換をすることでこのエラーを回避することができます。

Defined Typeとオペレーター

Defined Typeは、普通のtypeと同様に算術演算子(+, -, *, /)や比較演算子(==, >, <)が使えます。

ただし、元のtypeが算術演算子や比較演算子をサポートしていない場合は、利用することができません。

また、同じtypeから作成したDefined Type同士も使用不可です。

メソッドの定義

Defined Typeの応用として、メソッドの定義を学びましょう。

メソッド?関数ではなく?

B男
B男
KOUKI
KOUKI

ええ。メソッドと関数は全く別物ですので、間違えないようにしてください。

メソッドは、定義したDefined Typeを「receiver parameter」と呼ばれる拡張パラメータとして関数名の前に宣言します。

メソッドは、Go言語のアプリケーション開発において至る所で使われる便利な機能です。

次のように呼び出します。

サンプルコードを見てみましょう。

簡単ですね。もちろんパラメータ(receiver parameter)も渡すことが可能です。

パラメータの名前は任意の文字列を定義できますが、Go言語の慣習では、Defined Typeの先頭一文字の小文字表記で定義することが多い様です。

メソッドと関数

メソッドを定義していても関数の使い方は変わりません。下記のサンプルでは、メソッドの宣言に加えて、関数の引数も宣言しています。

KOUKI
KOUKI

メソッドは、クラス宣言と似てますね。Go言語にはクラスが存在しないのですが、これなら使いやすいかもしれません。

もちろん戻り値も返せます。

また、メソッドを使った場合でも関数と同様に名前が先頭大文字の場合は、外部ファイルから呼び出しが可能になります。

Pointer ReceiverとValue Receiver

Defined Typeにおけるポインタの概念について触れます。

まずは、次のサンプルコードを見てください。

このサンプルコードの実行結果はどうなると思いますか?ちょっと考えて見てください。

これまで勉強してきた通り、Go言語は値渡しの言語です。つまり、Double関数の引数に渡された値は、元々の値をコピーしたものが渡されます。

よって、このサンプルコードの実行結果は以下の様になります。

本当ならCalculated Valueには”8“が返されて欲しいのですが、”4“のままになっていますね。

これを”8“と出力したい場合はどの様にすれば良いでしょうか?

答えは、「ポインタ」を使うことです。

Double関数のレシーバーにポインタ「*」を付与しました。これをPointer Receiverと呼びます。逆に、ポインタが付与されていないレシーバーは、Value Receiverです。

出力結果を確認してみましょう。

期待した通りの値が出力されました。

簡単におさらいすると、ポインタは変数のメモリ上のアドレスを指し示しているものでした。ポインタを活用することで、このメモリ上のアドレスの値=変数の値を直接書き換えることが可能です。

ちなみにサンプルコード上で変更を加える場所は呼び出し先(Double)のみで、呼び出し元には何も手を加える必要はありません。

呼び出し先がPointer Receiverを必要にしていた場合、Go言語が自動的に引数をポインタとして解釈してくれるからです。

逆にReceiver PointerをValue Pointerとして自動解釈することもあります。

ポリモーフィズムっぽい動き

ポリモーフィズムは、オブジェクト思考プログラミングの概念の一つで、同じ名前のメソッドを複数のクラスで使用できるようにし、そのメソッドを通して、暗黙的に複数のインスタンスの動作を切り替えることができるようにします。

Go言語のDefined Typeは、これに近い実装ができます。

Title, SubTitle, BookInfoがそれぞれクラスのようなものだと思ってください。

main関数で、TitleとSubTitleを実体化し、それぞれ同じメソッド(getBookInfo)を呼び出しています。

結果はどうなるでしょうか?

それぞれのレシーバーが定義された関数が呼び出されましたね。

Go言語ではこのような使い方も可能な訳です。

まとめ

Defined Typeまとめ
・ 同じtypeで宣言したDefined TypeやTypeは型変換できる
->MyType(“test”)
・ 一度定義されたDefined Typeには他のtypeの値を型変換なしで格納することはできない
・ Defined Typeは、基底になったtypeのオペレータ(+, -など)を使用できる
・ Defined Typeをメソッドとして定義する時は、関数名の前に設定する
->fun (m Mytype) MyMethod(){}
・ メソッドを定義した関数でも引数や戻り値を定義できる
・ 同じ関数に異なるDefined Typeをメソッドとして定義できる
・ 同一パッケージ内には、一意のDefined Typeのみ設定できる
・ メソッドを呼び出す時は値渡しになるので、レシーバーにポインタを付与する

次回

次回は、EncapsulationとEmbeddingを学習しましょう^^

参考書籍

コメントを残す