~前置き~とりあえず簡単に理解しよう
Goには構造体とメソッドという概念があります。
言わずもがな、本気で理解しようとすると経験と知識が必要ですね。
なので今回は超初心者向けに、とりあえずこの二つの外面だけを理解しよう!という初心者の初心者による初心者のための記事を書きます。ええ。私も初心者ですとも。
もちろんqiitaには他にもGoに造詣が深い方が本格的な記事を書いてらっしゃいますし、そちらを見た方がいいです。(断言)
ただ、それをみる前にこの記事で概形をさらってから見るほうが多少分かりやすいかと思います。そういう記事ですこれは。サクッと読み流してください。
構造体とメソッドの簡単な説明
構造体とはなんぞや。
以下は構造体の一番初歩的な形です!
type Qiita struct{ //構造体を作っている
Field1 string
Field2 string
}
func main() {
//作った構造体に実際に値を入れて使う
qiita := Qiita{Field1: "これはフィールド1の値だぞ。", Field2: "これはフィールド2の値だぞ。"}
fmt.Println(qiita.Field1) //これはフィールド1の値だぞ。が出力される
}
簡単に説明していきます。
type Qiita struct {
Field1 string
Field2 string
}
このtype Qiita struct{}
というところで構造体を作っています。
Qiita
は構造体の名前で、自由に名前を付けることができますが、原則頭文字は大文字です。
Field1 string
Field2 string
はこの構造体に格納されたフィールド変数と呼ばれるものです。
フィールド変数名 型
の形で書きます。ここで変数の中に具体的な値を入れることはできません。
(Field1 := "qiita"
のようにはできない)
働きは変数とほぼ同じです。
つまりここではstring型のField1, Field2を格納した構造体Qiitaを作っているということです。
次にここ
qiita := Qiita{"これはフィールド1の値だぞ。", "これはフィールド2の値だぞ。"}
fmt.Println(qiita.Field1) //これはフィールド1の値だぞが出力される
qiita := Qiita{}
ここでQiita構造体を初期化しています。
そして{}のなかでフィールド変数に具体的な値を格納しています。
{フィールド変数名: 値, フィールド変数名: 値}
という形で値を入れます。
ちなみに、{値、値}
このようにフィールド変数名を省略した書き方もできます。
fmt.Println(qiita.Field1)
これはみなさんもうお分かりですよね?
qiitaには、具体的な値が入れられたQiita構造体が入っています。これはその中のField1
というフィールド変数を出力しているコードです。
構造体にわざわざ入れる意味あんの?
って思う人もいると思います。
色々メリットはありますが、とりあえず一つのジャンルの変数やメソッドをまとめることで見やすくできることもメリットの一つです。
メソッドの方を読み進めたら分かってくると思います。
メソッドとはなんぞや
ここからが本題ですかね
まず、前提として、一般の関数とメソッドは似ているが全くの別物です
メソッドとは超簡単に言うと、構造体にくっつけて使う関数のことです
以下はメソッドの初歩的な例です!
type Qiita struct{ //構造体
Field1 string
Field2 string
}
func (q *Qiita) combine() { //メソッド
fmt.Println(q.Field1 + "そして" + q.Field2)
}
func main() {
qiita := Qiita{Field1: "これはフィールド1の値だぞ。", Field2: "これはフィールド2の値だぞ。"}
qiita.combine() //これはフィールド1の値だぞ。そしてこれはフィールド2の値だぞ。が出力される
}
まず序盤の構造体を作っているところはさっきと同じです。
問題はここ。
func (q *Qiita) combine() { //メソッド
fmt.Println(q.Field1 + "そして" + q.Field2)
}
これがメソッドです。関数と似ていますが、関数名の前に(q *Qiita)というのがついてますね
これはレシーバーと呼ばれるものです。
レシーバーは(変数名 *くっつける構造体の名前)
というふうになっています。極論、この*の後の部分で、このメソッドがどの構造体のものなのか見分けることができます。
レシーバーとは、メソッドの中で構造体のフィールド変数を使うためのものです。
fmt.Println(q.Field1 + "そして" + q.Field2)
ここでq.Field1やq.Field2となっていますね。
もうわかったかと思いますが、qの中にQiita構造体が入っています。
なのでq.フィールド変数名
とすることで構造体のフィールド変数名を使うことができるのです。
次で最後です。
func main() {
qiita := Qiita{Field1: "これはフィールド1の値だぞ。", Field2: "これはフィールド2の値だぞ。"}
qiita.combine() //これはフィールド1の値だぞ。そしてこれはフィールド2の値だぞ。が出力される
}
ここでは先ほどと同じようにqiitaにQiita構造体を入れています。
そしてcombine()というメソッドは、Qiita構造体にくっついていますので、qiita.combine()という形で使うことができます。
ちなみに、関数と同じように書くことで、メソッドにも引数や戻り値を付けることは可能です
- メソッドは
func (変数 *構造体名) 関数名() 戻り値 {}
という形で書く - レシーバーの
*構造体名
を見ることで、そのメソッドがどの構造体のものか見分けられる - メソッドはレシーバーを使うことで、内部で構造体のフィールド変数を使える
ということですね。
まとめ
構造体とメソッドを超簡単に説明しました。
初心者がとっつくための記事ですので多少極端な言い方もあるかもしれませんが、ご理解ください。
このほかに、Goには似たようなのでインターフェースというものも存在します。
Goの作者の一人であるRuss Cox氏が
Go's interfaces―static, checked at compile time, dynamic when asked for―are,
for me, the most exciting part of Go from a language design point of view. If
I could export one feature of Go into other languages, it would be
interfaces.
"インターフェースを制す者はGoを制す"
というようなことをおっしゃっているようにとても重要なものです。
しかし、構造体とメソッドの説明に思ったより熱が入ってしまったので、とりあえずここで筆を置くことにします。
ありがとうございました。