1
1

More than 3 years have passed since last update.

Go言語の構造体の基本

Last updated at Posted at 2019-10-28

Go言語にはJavaなどの言語でいうクラスやというものがなく、構造体というデータをひとまとめにして扱うための仕組みを使ってクラスのような機能を提供します。

この構造体を使うことで、オブジェクト指向の継承のような実装を実現することが出来、Go言語の一つの大きな特徴になっています。

この記事では構造体の宣言の仕方から、実際にどのように扱われるのかまで見ていきます。

構造体の基本

構造体の宣言

Go言語の構造体は以下のように変数として宣言して使用できます。

var japanese struct {
    name string
    age int
}
japanese.name = "hanako"
japanese.age = 23
fmt.Println(japanese)

構造体は変数だけではなく、型として宣言することもでき、こちらの方がより広く使われています。

type person struct {
    name string
    age int
}

studentA := person{
    name: "Taro",
    age: 20,
}

fmt.Println(studentA)

構造体の型がクラスで、定義した構造体の型で変数を宣言するのがインスタンス変数を宣言するのに似ています。

また、構造体に構造体を埋め込むことが可能で、これにより継承を実現しています。継承したい構造体(親クラスに当たるもの)を構造体の中に定義します。

オブジェクト指向言語と同じように、親クラスに当たる構造体のフィールドには子クラスに当たる構造体からアクセスすることが可能です。

func main() {
    studentA := person{
        name: "Taro",
        age:  20,
    }
    taro := japanese{
        language: "Japanese",
        country:  "Japan",
        person:   studentA,
    }

    fmt.Println(taro)
        fmt.Println(taro.person.name) //埋め込まれている構造体の要素にアクセスできる
}

type person struct {
    name string
    age  int
}

type japanese struct {
    language string
    country  string
    person   person
}

構造体はクラスに相当する役割を果たすため、当然メソッドも定義できます。構造体にどうメソッドを定義すればいいのか見ていきましょう。

構造体にメソッドを定義する

構造体にメソッドを定義するには、定義先の構造体をレシーバに持つ関数を定義する必要があります。

実際に見てみましょう。これが構造体にメソッドを定義する例です。

type person struct {
    name string
    age  int
}

func (p person) selfIntro() {
    fmt.Printf("My name is %v. I'm %v years old.", p.name, p.age)
}

ご覧のように、personをレシーバに持つselfIntroというメソッドを定義しています。selfIntro()メソッド内部では、レシーバとして受け取った構造体が持つ変数にアクセスし、その変数の値を出力しています。

func main() {
    studentA := person{
        name: "Taro",
        age:  20,
    }
    fmt.Println(studentA)
    studentA.selfIntro() //出力結果: My name is Taro. I'm 20 years old.
}

これが実際に使用する場合の使用例です。

構造体の使用例

ここまでで構造体の基本について見てきました。ここからは構造体を使用することでコードをより読みやすくできる例をご紹介します。

以下の構造体は、天気予報の情報を定義している構造体の型です。現時点では最高気温と最低気温、緯度経度による位置情報が入っています。

type wheatherReport struct {
    high, low float64
    latitude, longitude float64
}

現時点では、この二つだけなのでまだ分かりやすいでしょう。しかし、この構造体に最高湿度と最低湿度、降水確率など新しい情報を入れようとすると、ややこしくなってしまいます。

type wheatherReport struct {
    highTemperature, lowTemperature float64
    highHumidity, lowHumidity float64
    latitude, longitude float64
}

新たに構造体を定義し、構造体を埋め込むことでこの問題を解決することが出来ます。

func main() {
        nara := wheatherReport{
        temperature: temperature{high: 21.2, low: 11.0},
        humidity: humidity{high: 55, low: 33},
    }
    fmt.Println(nara.humidity.high)
    fmt.Println(nara.temperature.high)

}

type temperature struct {
    high, low float64
}

type humidity struct {
    high, low float64
}

type location struct {
    latitude, longitude float64
}

type wheatherReport struct {
    temperature temperature
    humidity humidity
    location location
}

どうでしょう、一気に読みやすくなったかと思います。Go言語のコードを読んでいると、至る所で構造体が使われているので、しっかりと理解しておきましょう。

おまけ:構造体を初期化するコンストラクタ関数

オブジェクト指向の言語には、インスタンスをNewで作成した時に呼び出される機能があります。Pythonではinit、Rubyではinitialize、PHPでは__construct()です。

しかし、そのような仕組みがGoにはありません。その代わりとなるものがコンストラクタ関数です。

コンストラクタ関数は名前の先頭にnewという名前をつけて宣言するという慣習があります。

func newTemperature(high, low float64) temperature {
    return temperature{high, low}
}

このようにして、コンストラクタ関数で構造体を初期化するというやり方があるので覚えておくとよいでしょう。

それでは、最後までお読みいただきありがとうございました。

1
1
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1