前書き
具体的な詳細を中心に抽象化を構築することは、プログラミング言語が開発者に提供できる最大のツールです。 構造体により、Go開発者はGoプログラムが動作する世界を記述することができます。 Street
、City
、またはPostalCode
を記述する文字列について推論する代わりに、構造体を使用すると、代わりにAddress
について話すことができます。 これらは、将来の開発者(私たち自身を含む)にGoプログラムにとって重要なデータと、将来のコードがそのデータを適切に使用する方法を伝える取り組みにおいて、documentationの自然なつながりとして機能します。 構造は、いくつかの異なる方法で定義および使用できます。 このチュートリアルでは、これらの各テクニックを見ていきます。
構造の定義
構造体は、たとえば、税を申告するために使用できる紙のフォームのように機能します。 紙のフォームには、姓や名などのテキスト情報のフィールドが含まれる場合があります。 テキストフィールドに加えて、フォームには、「既婚」または「単一」などのブール値、または誕生日の日付フィールドを示すチェックボックスがあります。 同様に、構造体はさまざまなデータをまとめて収集し、さまざまなフィールド名で整理します。 新しい構造体で変数を初期化すると、フォームをコピーして入力できる状態になります。
新しい構造体を作成するには、まず構造体に含まれるフィールドを説明する青写真をGoに提供する必要があります。 この構造体の定義は通常、キーワードtype
で始まり、その後に構造体の名前が続きます。 この後、struct
キーワードに続けて、構造体に含まれるフィールドを宣言する中括弧{}
のペアを使用します。 構造体を定義したら、この構造体定義を使用する変数を宣言できます。 この例では、構造体を定義して使用します。
package main
import "fmt"
type Creature struct {
Name string
}
func main() {
c := Creature{
Name: "Sammy the Shark",
}
fmt.Println(c.Name)
}
このコードを実行すると、次の出力が表示されます。
outputSammy the Shark
この例では、最初にstring
タイプのName
フィールドを含むCreature
構造体を定義します。 main
の本体内で、タイプの名前Creature
の後に中括弧のペアを配置し、そのインスタンスのフィールドに値を指定することにより、Creature
のインスタンスを作成します。 c
のインスタンスでは、Name
フィールドが「SammytheShark」に設定されます。 fmt.Println
関数呼び出し内で、インスタンスが作成された変数の後にピリオドを置き、その後にアクセスするフィールドの名前を置くことにより、インスタンスのフィールドの値を取得します。 たとえば、この場合のc.Name
は、Name
フィールドを返します。
構造体の新しいインスタンスを宣言する場合、通常、最後の例のように、フィールド名とその値を列挙します。 または、構造体のインスタンス化中にすべてのフィールド値が提供される場合、次の例のようにフィールド名を省略できます。
package main
import "fmt"
type Creature struct {
Name string
Type string
}
func main() {
c := Creature{"Sammy", "Shark"}
fmt.Println(c.Name, "the", c.Type)
}
出力は最後の例と同じです。
outputSammy the Shark
クリーチャーのType
をstring
として追跡するために、Creature
にフィールドを追加しました。 main
の本体内でCreature
をインスタンス化する場合、各フィールドの値を順番に指定し、フィールド名を省略することで、より短いインスタンス化形式を使用することを選択しました。 宣言Creature{"Sammy", "Shark"}
では、Name
が最初に表示されるため、Name
フィールドは値Sammy
を取り、Type
フィールドは値Shark
を取ります。型宣言の後にType
が続きます。
この短い宣言形式にはいくつかの欠点があり、Goコミュニティはほとんどの状況で長い形式を好むようになりました。 短い宣言を使用する場合は、構造体の各フィールドに値を指定する必要があります。気にしないフィールドはスキップできません。 これにより、多くのフィールドを持つ構造体の短い宣言がすぐに混乱します。 このため、短いフォームを使用して構造体を宣言することは、通常、フィールドがほとんどない構造体で使用されます。
これまでの例のフィールド名はすべて大文字で始まっています。 これは文体的な好みよりも重要です。 フィールド名に大文字または小文字を使用すると、他のパッケージで実行されているコードがフィールド名にアクセスできるかどうかに影響します。
構造体フィールドのエクスポート
構造体のフィールドは、Goプログラミング言語内の他の識別子と同じエクスポートルールに従います。 フィールド名が大文字で始まる場合、構造体が定義されたパッケージの外部のコードによって読み取りおよび書き込み可能になります。 フィールドが小文字で始まる場合、その構造体のパッケージ内のコードのみがそのフィールドを読み書きできます。 この例では、エクスポートされるフィールドとそうでないフィールドを定義します。
package main
import "fmt"
type Creature struct {
Name string
Type string
password string
}
func main() {
c := Creature{
Name: "Sammy",
Type: "Shark",
password: "secret",
}
fmt.Println(c.Name, "the", c.Type)
fmt.Println("Password is", c.password)
}
これは出力されます:
outputSammy the Shark
Password is secret
前の例にsecret
というフィールドを追加しました。 secret
はエクスポートされていないstring
フィールドです。つまり、Creature
をインスタンス化しようとする他のパッケージは、そのsecret
フィールドにアクセスまたは設定できません。 この例のように、同じパッケージ内でこれらのフィールドにアクセスできます。 main
もmain
パッケージに含まれているため、c.password
を参照して、そこに格納されている値を取得できます。 エクスポートされたメソッドによって仲介される構造体へのアクセス権を持つ、エクスポートされていないフィールドを持つことが一般的です。
インライン構造
構造体を表す新しい型を定義することに加えて、インライン構造体も定義できます。 これらのオンザフライの構造体定義は、構造体型の新しい名前を発明するのに労力が無駄になる状況で役立ちます。 たとえば、テストでは構造体を使用して、特定のテストケースを構成するすべてのパラメーターを定義することがよくあります。 その構造体が1つの場所でのみ使用されている場合、CreatureNamePrintingTestCase
のような新しい名前を思い付くのは面倒です。
インラインの構造体定義は、変数の割り当ての右側に表示されます。 定義した各フィールドに値を追加した中括弧のペアを追加することにより、すぐにそれらのインスタンス化を提供する必要があります。 次の例は、インライン構造体の定義を示しています。
package main
import "fmt"
func main() {
c := struct {
Name string
Type string
}{
Name: "Sammy",
Type: "Shark",
}
fmt.Println(c.Name, "the", c.Type)
}
この例の出力は次のとおりです。
outputSammy the Shark
この例では、type
キーワードを使用して構造体を記述する新しい型を定義するのではなく、短い代入演算子:=
の直後にstruct
定義を配置することによってインライン構造体を定義します。 前の例のように構造体のフィールドを定義しますが、すぐに別のペアのブレースと各フィールドが想定する値を指定する必要があります。 この構造体の使用は以前とまったく同じになりました。ドット表記を使用してフィールド名を参照できます。 インライン構造体が宣言される最も一般的な場所はテスト中です。これは、特定のテストケースのデータと期待値を含むように1回限りの構造体が定義されることが多いためです。
結論
構造体は、情報を整理するためにプログラマーによって定義された異種データのコレクションです。 ほとんどのプログラムは膨大な量のデータを処理し、構造体がないと、どのstring
またはint
変数が一緒に属していたか、またはどちらが異なっていたかを思い出すのが難しくなります。 次回、変数のグループをジャグリングしていることに気付いたときは、struct
を使用してそれらの変数をより適切にグループ化できるかどうかを自問してください。 これらの変数は、ずっと高いレベルの概念をずっと説明している可能性があります。