Go言語(プログラミング)入門メモ⑩

## 構造体(struct)
構造体は複数の値をまとめたもの。構造体とメソッドを組み合わせて使用することでほかの言語でいうところのオブジェクトのような使い方をすることができる。

## 構造体の定義
まず、main関数の外で、Vertexという名前の構造体を作成し、{}の中に2つのint型の値XとYを書く。main関数で構造体Vertexを変数vに代入する。この時「Vertex{X :1,Y :2}」のように書いて、構造体Vertexを初期化する。構造体がもつ値のことをフィールド、という。
~~~
type Vertex struct{        //構造体Vertexを作成
    X int
    Y int
}

func main() {
    v := Vertex{X :1,Y :2}　　//構造体Vertexを初期化して変数vに代入
    fmt.Println(v)　　　　　　 //構造体を表示　　
}

//以下のように表示される
{1 2}
~~~
構造体の中身を確認するには、「v.X」のように書く。
~~~
 v := Vertex{X :1,Y :2}
 fmt.Println(v)
 fmt.Println(v.X, v.Y)

 //以下のように表示される
 {1 2}
 1 2
 ~~~
 構造体の中身を書き換えるには、「v.X = 100」のように書く。
 ~~~
  v := Vertex{X :1,Y :2}
 fmt.Println(v)
 fmt.Println(v.X, v.Y)
 v.X = 100
fmt.Println(v.X, v.Y)

  //以下のように表示される
 {1 2}
 1 2
 100 2
 ~~~
 構造体の一部だけを初期化して宣言することもできる。Ｘだけを初期化するとＹは初期値である0になる。
 ~~~
 v2 := Vertex{X :1}
 fmt.Println(v2)

 //以下のように出力される
 {1 0}
 ~~~
 string型の場合、初期値は空の文字列になる。構造体Vertexにstring型のＳを追加し、初期化せずに表示すると、ＸとＹの値のあとに空の文字列が追加されることが分かる。

 ~~~
 type Vertex struct {
    X int
    Y int
    S string
 }

 func main() {
    v2 := Vertex{X: 1}
    fmt.Println(v2)
 }

 //以下のように出力される
 {1 0 }
~~~
 フィールドを指定せずに初期化する場合、「Vertex{1,2,"test"}」のように構造体に書いた順番で書く。また、「Vertex{}」のように書いて初期化すると、初期値になる。
 ~~~
 v3 := Vertex{1,2,"test"}
 fmt.Println(v3)

 v4 := Vertex{}
 fmt.Println(v4)

 //以下のように出力される、
 {1 2 test}
 {0 0 }
~~~

構造体のすべての値を初期値で初期値化する方法として、「Vertex{}」と書くほかに
「ver v5 Vertex」と書く方法もある。

~~~
var v5 Vertex
fmt.Println(v5)

//以下のように出力される
{0,0 }
~~~
## 構造体とポインタ
「new(Vertex)」とかくと、「&{0 0 }」とアドレスがついて表示される
~~~
v6 := new(Vertex)
fmt.Println(v6)

//以下のように表示される
&{0,0 }
~~~
ここで、データ型を確認してみると、newで作成したv6だけが*がついて表示されるため、ポインタになることがわかる。
~~~
v4 := Vertex{}
fmt.Println("%T %v\n", v4, v4)

var v5 Vertex
fmt.Println("%T %v\n", v5, v5)

v6 := new(Vertex)
fmt.Println("%T %v\n", v6, v6)

//以下のように出力される
main.Vertex{0 0 }
main.Vertex{0 0 }
*main.Vertex&{0 0 }    ←newなのでポインタになる
~~~
「&Vertex{}」のように&をつけて書くと、newで作成したときと同様にポインタになる。
~~~
v7 := &Vertex{}
fmt.Println("%T %v\n", v7, v7)

//以下のように出力される
*main.Vertex&{0 0 }
~~~
newで作成するよりも「&Vertex{}」のようにアドレスをつけた状態で宣言したほうがポインタが返ってくることが明示的なためよく使われる。

構造体のポインタの扱い方について、構造体Vertexを引数にとるchangeVertex関数を作成し、構造体の値Xに1000を代入する。main関数内で、構造体Vertexを初期化して変数vに代入し、changeVertexの引数に指定して実行する。

~~~
func changeVertex (v Vertex) {
    v.X = 1000
}

func main() {
    v := Vertex{1,2, ""test}
    changeVertex(v)
    fmt.Println(v)
}

//以下のように出力される
{1 2 test}
~~~
xの値が1000ではなくて1と出力されてしまっている。このとき、changeVertex関数には変数vの構造体そのものではなく、中身の値をコピーしたものを渡しているので、コピーされた構造体にchangeVertexでXに1000を代入している。そのため、main関数でvのXの値である1は書き換わっていない。構造体のフィールドの値をchangeVertex関数内で変更したいときは、ポインタを渡す必要がある。

そこで、changeVertex2関数を作成する。これは引数のVertexに*がついてポインタになっている。main関数内で、構造体Vertexに&をつけて初期化し、ポインタを変数v2に代入する。
~~~
func changeVertex2 (v2 *Vertex) {
    v.X = 1000
}

func main() {
    v2 := &Vertex{1,2,"test"}
    changeVertex2(v2)
    fmt.Println(v2)
}

//以下のように出力される
&{1000 2 test}
~~~

## 学習に使用した教材
・『入門】Golang基礎入門 + 各種ライブラリ + 簡単なTodoWebアプリケーション開発(Go言語)』M.A EduTech
https://www.udemy.com/course/golang-webgosql/?utm_medium=udemyads&utm_source=bene-msa&utm_campaign=responsive&utm_content=top-1&utm_term=general&msclkid=81e2f24a32cc185d275d953d60760226&couponCode=NEWYEARCAREERJP

・『シリコンバレー一流プログラマーが教える Goプロフェッショナル大全』酒井 潤 (著)
https://www.amazon.co.jp/%E3%82%B7%E3%83%AA%E3%82%B3%E3%83%B3%E3%83%90%E3%83%AC%E3%83%BC%E4%B8%80%E6%B5%81%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9E%E3%83%BC%E3%81%8C%E6%95%99%E3%81%88%E3%82%8B-Go%E3%83%97%E3%83%AD%E3%83%95%E3%82%A7%E3%83%83%E3%82%B7%E3%83%A7%E3%83%8A%E3%83%AB%E5%A4%A7%E5%85%A8-%E9%85%92%E4%BA%95-%E6%BD%A4/dp/4046070897