Go言語のポインタ、一緒に仲良くなろう！

## はじめに

本記事は、**Go言語のポインタについて** について記述しております！！

## 本記事で学べること

本記事を通して学べることは、
- ポインタとは
- Go言語でのポインタの使用方法

## 本記事の流れ

| 目次 |
|:-------------|
| [1. ポインタとは](#1-ポインタとは) |
| [2. ポインタを理解する上で必要なこと](#2-ポインタを理解する上で必要なこと) |
| [3. Go言語でのポインタの使用方法](#3-Go言語でのポインタの使用方法) |

## 1. ポインタとは

ポインタとは、変数などのメモリのアドレスを保持する特殊な変数です。
このアドレスは、メモリ上の位置を示しポインタを通じてその位置にアクセスしてデータの読み書きすることができる。
ポインタを知るには、`コンパイル・変数・メモリ・アドレス`を理解する必要があります。
それでは、ポインタを理解できるように前提の話をしていきます。

## 2. ポインタを理解する上で必要なこと

コンパイル
Go言語は、記述したソースコードをそのままコンピュータに読ますことが出来ないため一度コンパイルをして**バイナリーコード**(コンピュータが読めるコード)に変更する必要があります。
→**バイナリーコード**とは、コンピュータが読みやすい言葉で`0 or 1`この2つの数字で書かれているものです。

このコンパイルの過程で変数はメモリ上の特定の位置に割り当てられます。
その位置をアドレスと言います。
そのコンパイル時に
要するに、、、
コンパイル時にメモリ上のどこかに変数を割り当ててその割り当てた`場所`のことを**アドレス**という

そして、ポインタを理解する上で必要になってくるのが、`変数` `メモリ` `アドレス`　です。
これらを理解することによりポインタへの理解が深まります。

コードで説明をしていきます。

```golang:main.go
package main

import "fmt"

func main() {
    variable := "変数"
}
```

```terminal
go run main.go
```

 `go run main.go` のコマンドを実行することにより指定ファイルを**コンパイル→実行**をしてくれます。
コンパイルの際に`main.go`ファイルの`main関数`に記述されている、`variable`という変数がメモリのどこかに割り当てられます。
そしてその変数が割り当てられた場所がアドレスになります。

次は、そのアドレスを実際に表示させましょう。

## アドレスの出力

Go言語で実際にアドレスを表示していきたいと思います。
Go言語で`アドレス`を表示させるためには、`&`を使用します。

```golang:main.go
package main

import "fmt"

func main() {
    variable := "変数"
    fmt.Println(&variable) // variableのメモリアドレスを表示
}
```

```terminal
0xc00009e020
```

このような値が出力されれば`アドレス`の出力の成功です。
上記のように`&`を使用して変数のアドレスを出力させることができます。

アドレスを使用できるようになると、どのようなメリットがあるというと`メモリのアドレスに格納された変数の値が変更できる`というメリットがあります。

例えば
```golang:main.go
package main

import "fmt"

type Product struct {
	Name  string
	Price int
}

func main() {
	var p Product

	p = Product{
		Name:  "コーヒー",
		Price: 200,
	}
	p2 := &p
	p2.Name = "紅茶"
	p2.Price = 300
	fmt.Print(p)
	fmt.Print(p2)
}
```

```terminal:出力結果
{紅茶 300}&{紅茶 300}
```

上記のコードのように書くと`p` / `p2`が同じ値になります。

なぜ値が同じになっているかを説明するためにコードを順に解説すると
- Productという構造体の`変数p`を定義する
- pという変数の中に値を入れる `Name: "コーヒー"` / `Price: 200`
- `&p`でアドレスを指しているので`p2`には、`pのアドレス`を変数の値として格納します。
- これによりp2という変数名ですが、pとp2は同じものを指しているようになります。
- その上でp2(pのアドレス)のNameとPriceを変更させているので`p`のアドレスにあるName / Priceの値を変更しているようになる

上記の流れによりp2を変更するとpの値を変更されることになります。

**ポインタ** があることにより`値だけを渡す方法`と`変数のアドレスを渡し元の変数の値自体を書き換える`ことができます。

それをコードに書いていきます。

```golang:main.go
package main

import "fmt"

type Product struct {
	Name  string
	Price int
}

func main() {
	var p Product

	p = Product{
		Name:  "コーヒー",
		Price: 200,
	}
    // pの値を表示
	fmt.Print(p)

    // pの値をだけを渡す方法(p2を変更してもpの値は変更されない)
    p2 := p
	p2.Name = "カフェラテ"
	p2.Price = 400

    // pのアドレスを変数に格納をする(p3はpのアドレスなのでp3を変更すると`p`の値が書き換わる)
	p3 := &p
	p3.Name = "紅茶"
	p3.Price = 300

    // p3によって書き換えられた値
	fmt.Print(p)
    // p2の値
	fmt.Print(p2)
    // p3の値
	fmt.Print(p3)
}
```

```terminal:出力結果
{コーヒー 200}
{紅茶 300}
{カフェラテ 400}
&{紅茶 300}
```

上記のように出力されます
コードの説明をしていきます。

```golang:main.go
type Product struct {
	Name  string
	Price int
}
```

`Product`という構造体の定義

```golang:main.go
	var p Product

	p = Product{
		Name:  "コーヒー",
		Price: 200,
	}
    // pの値を表示
	fmt.Print(p)
```

Productという構造体の`p`変数を宣言する
`p`の変数に値を格納している
`p`の値を出力している

```golang:main.go
    // pの値をだけを渡す方法(p2を変更してもpの値は変更されない)
    p2 := p
	p2.Name = "カフェラテ"
	p2.Price = 400
```

`p`の変数の値を`p2`に格納している
- この時に`p`は、`p2`に対して **値のみ** を渡している(値渡し)

p2の値に対して`Nameには、カフェラテ` / `Priceには、４００` を入れている。

```golang:main.go
    // pのアドレスを変数に格納をする(p3はpのアドレスなのでp3を変更すると`p`の値が書き換わる)
	p3 := &p
	p3.Name = "紅茶"
	p3.Price = 300
```

`p`の変数のアドレスを`p3`に格納している
- この時に`p3`に格納しているのは、`p`のアドレスを`p3`に格納しているつまり、`p3`は`p`と同じアドレスを指していることになります。(参照渡し)

p3の値に対して`Nameには、紅茶` / `Priceには、300` を入れている。
**※ ここで`p2`と大きく違うのは、`p2`はあくまで`p`から値を渡されただけでp2とpは 違うアドレス なのでp2の値を変更したとしてもpに対して何も影響が出ないのに対して`p3`は`p`と同じアドレスを指しているためp3が値の変更があった場合`p`もその変化に伴って`p`の値も変化するということになる。**

このようにしてポインタを使用した場合と使用していない場合でコードの使い分けができます。

これでポインタについての理解が少し深まったと思います。
それでは次にポインタ型について説明をしていきます。

## ポインタ型

ポインタ型とは、メモリ上のアドレスを記憶する変数の型
**※ポインタ型は、派生型なので単体での型定義はできない(Int Stringなどと併用して使用する)**

下記に例を記述します。

```golang:main.go
package main

import "fmt"

type Product struct {
    Name string
    Price  int
}

func main() {
    var p *Product

    p = &Product{
        Name: "太郎",
        Price:  200,
    }
    fmt.Print(p)
}
```

```terminal:出力結果
&{太郎 200}
```

コードの説明をしていきます。
※これまでに説明をしてきた構造体の定義などは、省略させていただきます。

```golang:main.go
    var p *Product

    p = &Product{
        Name: "太郎",
        Price:  200,
    }
    fmt.Print(p)
```

`*Product`の`*`によってProductのポインタ型として宣言している。
そしてpが`ポインタ変数`として宣言をしており値の格納をしている

上記の内容は、Productという構造体を`*`を使用してポインタ型として宣言をしておりポインタ型を格納しているその構造体を変数`p`として宣言している。
※ポインタ型の構造体の変数のことを`ポインタ変数`と呼ぶ


## 応用

次にこれまでの内容から応用を一つ出していきたいと思います。

- 変数を宣言する
- 宣言した変数を新たに宣言した変数に`参照渡し`で値を格納する
- 参照渡しをした変数に対して値の変更をする

方法について記述をしていきます。

```golang:main.go
package main

import "fmt"

func main() {
    product := "コーヒー"

    // productのアドレスをp2に格納する→(p2に入るのは、productのアドレスとそのアドレスにあるproduct="コーヒー"→*string)
    p2 := &product

    // p2の値を変更するのに必要なのはアスタリスク(*)が必要
    *p2 = "紅茶"

    // p2のアドレス(productのアドレス)
    fmt.Print(p2)
    
    fmt.Printf(product)
    // p2の値(productの値)
    fmt.Printf(*p2)
}
```

このようにしてp2側でpの値の変更が可能になる


## 最後に

今回は、Go言語のポインタについて記述いたしました。

ご指摘点などがございましたら、コメントをいただけると幸いです。