Go言語 ~基礎編~ Struct

go

今回は、Structについて学びます。

StructもArray, Slice, Mapと同様にデータ構造体です。

しかし、Structは他のデータ構造とは違って「複数種類のタイプを格納できる」超便利なやつです。

Structは、あらゆるプログラムの中で使用される超重要項目であるため、しっかり学んでいきましょう。

学習記事まとめ

Structについて

Sliceはリスト形式で、MapはKey-Valueの形式で値を格納しました。この二つの構造体で共通している点が、「一つのタイプしか格納できないこと」です。

しかし、Structにはその制約はありません

Structは、複数の異なるタイプで構成することができるデータ構造体です。

サンプルプログラムを書いてみます。

出力結果を見るとstructもSliceやMapと同様に基底typeのデフォルト値で初期化されていますね。

フィールドアクセス

Structの宣言はできたので、次は、フィールドにアクセスしてみます。

タイプとして宣言

ここまでのStructは大変便利そうに見えますが、複数宣言したいときは少し厄介です。

ご覧の通り、Structのプロパティが重複した状態で宣言する必要があります。これは、プログラムの観点から言うとイケてないです。

しかし、安心してください。ちゃんと回避策があります。

それは、Go言語のtypeを自分で作成するばいいのです

Go言語には、string, int, bool, float64などの基底typeが存在しますが、自分でカスタムしたtypeを「type」キーワードで宣言することができます。

typeにもスコープがあり、関数内に宣言してしまうとその関数内でしか使用することができません。その為、通常はパッケージレベルで宣言します。

先ほどのコードを書き換えてみます。

随分とスッキリしたことが分かると思います。

パラメータとして宣言

structは、パラメータとして宣言することもできます。

Structを受け取って、情報を出力するプログラムです。実行します。

逆にstructを返す実装をしてもいいかもです。

Structの値渡し

Structは、値渡しの挙動をとります。次のサンプルコードを見てください。

setPropertyにstructを渡して値を設定しましたが、出力結果はそれぞれのtypeのデフォルト値になっています。

この挙動は、以前学習した「関数の引数の実態」と同じです。

setProperty関数の引数として渡されたのは、student Structをコピーしたもので、実態ではありません。

そうそう、これってバグになりやすいんだよな〜

B男
B男
KOUKI
KOUKI

…(それ、以前私が言いました…)

回避策は、「ポインタ」を使うことです。

簡単ですね。しかし、疑問が残ると思います。

前回とは違って、今回のコードは少し違っています。

前回のコードを以下に記載しますね。

KOUKI
KOUKI

違いがわかるでしょうか?

わかったわ。double関数内のamount変数には*がついてるけど、setProperty関数内の各変数には*がついてない!どうやって動いているの?

A子
A子

ちょっと複雑なので少しずつ解説します。

まず、ポインタは変数のアドレスを指し示しています。

アドレスではなく、値を取得したい場合は、pointerの頭に*をつけます。

こういった背景があり、structの変数にも*が必要ではないのか?といった疑問が湧いてきます。

しかし、structのポインタに*をつけると正しく動作しません。

「*s.name」にした場合、Go言語は「name」がポインタであると判断してしまいますが、nameにはstringが宣言されているだけですので、エラーになります(他の変数も同様)。

つまり、次のように実装するとエラーが回避できます。

KOUKI
KOUKI

普通は、*なしで書きますけどね。

Structの外だし

Structを外部パッケージに外出ししてみましょう。

注意点としては、Structの変数名とフィールド名の先頭は必ず大文字で始める必要があります

先頭大文字で宣言することで、外部パッケージからの呼び出しが可能になるのです。

Structリテラル

Structリテラルを使えば、宣言&初期化が一度に行えます。

フィールドの共有

Structは便利な構造体で、どのようなtypeでも格納可能です。それはつまり、Structで宣言したtypeも格納可能であるということです。

Anonymous Struct fields

Struct Typeを他のStructに入れると便利だということはわかりましたが、少しめんどくささも感じています。

例えば、次のサンプルコードでは、StudentInfoを跨いで値を格納していますが、少し見た目が悪いです。

こういった場合にGo言語では、「anonymous fields」と呼ばれるStructフィールドが用意されています。

このフィールドを利用するとより簡単にプロパティへアクセスできます。

PersonalInfoのフィールド名を削除しました。main.goも書き換えましょう。

ご覧の通り、StudentInfo無しででアクセス可能になりましたね。随分とスッキリしました。

まとめ

KOUKI
KOUKI

本項で学んだことをまとめます。

Struct まとめ
・ structキーワードで、Structを宣言する -> var myStruct struct {}
・ typeキーワードで、独自のtypeのstructを宣言できる
-> type myType struct{}
・ 「.」でプロパティにアクセスできる -> myStruct.field1 = “value”
・ Structが関数に渡される際、コピーされたものが渡される(値渡し)
・ 呼び出し元で宣言したstructを渡したい場合は、ポインタを用いる
・ Structを外部から呼び出したい場合は、名前の先頭を大文字にする
・ 同様にフィールド名も先頭大文字にする
・ Structリテラルで、宣言&初期化が行える -> myVar := myType{field: value}
・ Structには、anonymous fieldを宣言できる

次回

次回は、Typeの宣言についてより詳細に学んでいきましょう。

参考書籍

コメントを残す