Goのポインタについて改めて理解する

# はじめに

Go言語を仕事で使うようになってちょうど1年ほど経ちました。

今更ながら分かっているようで分かってないポインタについてきちんと理解しようと思い今回改めて勉強をしました

[今回読んだ書籍](https://techbookfest.org/product/5039923363053568?productVariantID=5673208908873728)

Goのversionは`1.21`を使用しています。

# ポインタの挙動

例えば以下のようなコードがあったとします

```go
package main

import "fmt"

type Item struct {
	value string
}

func main() {
	items := []Item{{value: "A"}, {value: "B"}, {value: "C"}}
	pointerList := make([]*Item, 0, len(items))

	for _, i := range items {
		pointerList = append(pointerList, &i)
	}

	for _, p := range pointerList {
		fmt.Println(p.value)
	}
}
```

この実装の出力結果として下記の結果を期待していますが

```go
A
B
C
```

実際に出力されるのは、

```go
C
C
C
```

になります。

なぜこのような挙動になるのか、期待した出力結果にするにはどうすればいいのかがわかるようになるのが今回のゴールです。

※ Goのversion`1.22`でメモリの再利用に関して変更が加えられているので今回の記事の挙動とは異なるので注意
https://tech.anti-pattern.co.jp/go1-22de/

# Goにおける値の代入と参照の代入の挙動の違い

まずはGoにおける変数に値を割り当てる値の代入と参照の代入の挙動の違いついて理解していきます

### 値の代入

Goでは、基本型（int、stringなど）や 構造体（struct）は値の代入になります

これは、変数に別の変数の値を代入するときに、その値のコピーが作成されるという意味です

以下の例を見てみましょう。

```go
package main

import "fmt"

type Item struct {
    value string
}

func main() {
    a := Item{value: "A"}
    b := a // 値のコピー
    b.value = "B"
		fmt.Println("a.value", a.value) // A
		fmt.Println("b.value", b.value) // B
}
```

値の代入では、`a`の値が`b`にコピーされます。その後、`b.value`を変更しても、`a.value`には影響を与えません。

これは、`b`が`a`のコピーであり、`a`とは独立した存在であるためです。

### 参照の代入

- Goでは、ポインタを使うことで参照の代入を行うことができます
- 参照の代入とは、変数が別の変数のアドレス（メモリ位置）を参照することを意味します

次の例を見てみましょう

```go
package main

import "fmt"

type Item struct {
    value string
}

func main() {
    a := Item{value: "A"}
    b := &a // ポインタを代入
    b.value = "B"
		fmt.Println("a.value", a.value) // B
		fmt.Println("b.value", b.value) // B
}
```

参照の代入では、`b`は`a`のアドレスを参照しています。したがって、`b.value`を変更すると、`a.value`も変更されます。

これは、`b`が`a`のメモリ位置を指しているため、実際には同じデータを指しているからです。

### Goの特定の参照型

Goの特定の型（slice、map)ではポインタ型でなくてもデフォルトで参照渡しされます

例えば、sliceの場合をみていきます

```go
package main

import "fmt"

func main() {
    a := []string{"A", "B", "C"}
    b := a // スライスの参照をコピー
    b[0] = "Z"
    fmt.Println("a:", a) // [Z B C]
    fmt.Println("b:", b) // [Z B C]
}
```

 `b := a` でスライスの参照をコピーするため、`b`と`a`は同じデータを指すようになります

その後スライスの最初の要素を`"Z"`に変更し出力してみると`a`と`b`は同じ結果になっています

sliceでは内部的にポインタを使用しているため`b`を変更すると、`a`も変更されるというわけです

# メモリとアドレス

ポインタの理解するためにはメモリの構造とそのアドレス指定方法を理解することが不可欠です。

実際にGo言語におけるメモリとアドレスの基礎について解説します。

### メモリの基本構造

メモリは、データを格納するための領域です。

メモリはバイト（8ビット）単位で区切られ、それぞれのバイトに一意の数字が割り当てられます。このバイトに割り当てられている数字がアドレスと呼ばれます。

例えば、メモリの最初のバイトのアドレスが `0x00000000` であれば、その隣のバイトのアドレスは `0x00000001` になります。このアドレスを用いることで、プログラムは特定のメモリ位置にアクセスし、データの読み書きを行っています。

イメージとしてはこんな感じです。

![スクリーンショット 2024-07-21 17.55.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/5dc5027e-2ec9-389c-d211-e47aaa13e186.png)


### 値とアドレスの違い

普段のプログラミングでは、メモリの構造を意識することはほとんどないですが、ポインタを理解するには意識する必要があります。

なぜなら、ポインタがメモリのアドレスを指し示す特殊な型だからです。

実際にデータがどのようにメモリに格納されているのかを見ていきます。

**通常型のメモリ配置**

以下のコードでは、int 型の変数`a`の値とアドレスを出力しています。

Go言語では変数に接頭辞として&(アンパサンド)を付与することでアドレスを取得することができます。

```go
package main

import "fmt"

func main() {
    var a int
    fmt.Printf("value: %d\n", a)
    fmt.Printf("address: %p\n", &a)
}
```

実行結果

```go
value: 0
address: 0x1400009c018
```

実行してみると`a`の値は`0`で`a`のアドレスは`0x1400009c018` となりました。

以下の図はここで出力した`a`がどのようにメモリに格納されているかを模式的に表したものです。

![スクリーンショット 2024-07-21 17.59.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/53e2507c-7917-4655-b66b-1d398ec45752.png)


図にある**int型のメモリサイズ**とはGoでのint型のメモリサイズは一般的には8バイトになるのでこの変数`a`はメモリ上の8バイトを専有しています。

次にアドレスである`0x1400009c018` は変数`a`がメモリ上の8バイトを専有しているので8つの番号がつけられた領域にまたがってデータが格納されていてその8つの番号の一番若い番号が**aが示す領域の先頭のアドレス**`0x1400009c018` になります。

つまりaは`0x1400009c018` を先頭とする8つの1バイトの領域にデータが格納されているわけです。

最後に`a`の値をみると図では**この領域の値**と書きました。

この`a`は8バイトつまり64ビットのデータ領域を専有していて、これは0か1の数字が64個並んでいることを意味しています。

`a`は8バイトのint型なので、64個の0と1の組み合わせを使って`-9,223,372,036,854,775,808` から `9,223,372,036,854,775,807` までの整数値を表すことができます。

なので、`a`の値が0であるということはこの64個の0と1の組み合わせを使って表された整数値が0であるので、今回の場合だと64個の0がこのaの8バイトの領域に並んでいることになります。

**ポインタ型のメモリ配置**

Goでは通常型の先頭に「`*`」(アスタリスク)を付与することでその型を**ポインタ型**と表すことができます。

通常型とポインタ型は全く別のものになります。

`int`型のポインタ型である*int型を使い詳しく見ていきます。

`*int` 型の変数`b` を定義し、その値とアドレスを出力しています。

```go
package main

import "fmt"

func main() {
    var b *int
    fmt.Printf("value: %p\n", b)
    fmt.Printf("address: %p\n", &b)
}
```

実行結果

```go
value: 0x0
address: 0x140000a2018
```

bの値は`0x0` になりbのアドレスは`0x140000a2018`になりました。

こちらも図で見ていくと、

![スクリーンショット 2024-07-21 18.01.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/95e2fbb4-cb62-61dd-34fa-7b8a064ab28e.png)


`*int` ****型のメモリサイズはGoでは8バイトとなるのでこの変数bはメモリ上の8バイトを専有しています。

次にアドレスである`0x140000a2018` は前述の変数aと同様に専有する8バイトの領域のうち先頭のメモリ上の番号を表しています。

そして`b`の値を見ていくと、先ほどの変数`a`では`-9,223,372,036,854,775,808` から `9,223,372,036,854,775,807` までの整数値を格納できましたが変数`b`ではアドレスを値として格納することができます。

どういうことかというと、メモリは1バイトごとに領域が区切られていてそれぞれ番号がつけられていると説明しましたが、その番号そのものをメモリ領域に格納できるということです。

ただし格納できるのはその型に対応するポインタ型の変数のアドレスのみで、`*int`型の変数には`int`型の変数のアドレスしか格納できないということです。

なので今回変数bには値を何も代入していないので、bの値はゼロ値になります。つまり8バイトの64個の全てのビットが0になるのでbの値は`0x0` となります。なおGoでは値が`0x0` はnilと同義です。

# メモリ配置とデータへのアクセス

続いてポインタを理解する上で欠かせない**直接参照**と**間接参照**について理解していきます。

**直接参照**と**間接参照**を理解するための前段階として**型サイズ**、**オフセット**、**コピー代入**についてそれぞれ解説していきます。

### 型サイズ

型サイズとは、データ型ごとにメモリ上で確保される領域の大きさのことです。

Go言語では、型サイズは`unsafe`パッケージの`Sizeof`関数を使って取得することができます。

型によってどれくらい型サイズが違うのか試しにプリミティブ型のサイズを出力してみます。

```go
package main

import (
    "fmt"
    "unsafe"
)

func main() {
    fmt.Printf("bool: %d\n", unsafe.Sizeof(false))
    fmt.Printf("int: %d\n", unsafe.Sizeof(int(0)))
    fmt.Printf("float64: %d\n", unsafe.Sizeof(float64(0.0)))
    fmt.Printf("string: %d\n", unsafe.Sizeof(""))
}
```

実行結果

```go
bool: 1
int: 8
float64: 8
string: 16
```

この型サイズは型によって決まるのであって値によって決まるわけではありません。

例えば、`int`型の場合値が0でも1でも型サイズは8バイトになります。

次に構造体の型サイズとポインタの型サイズを出力してみます。

```go
package main

import (
	"fmt"
	"unsafe"
)

type X struct {
	a int
	b float64
	c string
}

func main() {
	x := X{}
	fmt.Printf("X: %d\n", unsafe.Sizeof(x))
	fmt.Printf("X pointer: %d\n", unsafe.Sizeof(&x))
}
```

実行結果

```go
X: 32
X pointer: 8
```

型X はint, float64, string型で構成されていてフィールドの型サイズはそれぞれ8バイト、8バイト、16バイトになります。

このようにフィールドが定義された順にメモリ上に連続して並んでいるのが構造体のデータ構造です。なのでフィールド型のサイズの合計が構造体の型サイズになります。

今回の場合だと8バイト、8バイト、16バイトを足し合わせた32バイトが型Xの型サイズになります。

一方Xのポインタ型である型*Xのサイズ出力結果を見るとは8バイトになっています。

ポインタは*intなども含め**全て同じ8バイトになります**。（あくまで64bitマシンの場合）

### オフセット

構造体のデータ構造はフィールドの値が連続して並んでいます。

そのフィールドにアクセスするには先頭のアドレスから何バイト目にデータがあるかがわかればアクセスすることができます。

この先頭アドレスからの距離をオフセットと言います。

Goでは`unsafe`パッケージの`Offsetof`関数を使用することでオフセットを取得することができます。

```go
package main

import (
	"fmt"
	"unsafe"
)

type X struct {
	a int
	b float64
	c string
}

func main() {
	x := X{}
	fmt.Printf("x.a: %d\n", unsafe.Offsetof(x.a))
	fmt.Printf("x.b: %d\n", unsafe.Offsetof(x.b))
	fmt.Printf("x.c: %d\n", unsafe.Offsetof(x.c))
}
```

実行結果

```go
x.a: 0
x.b: 8
x.c: 16
```

実行結果から分かるように、

`x.a`のオフセットは0なのでフィールド`a`のデータは先頭から0バイト目に格納されていることがわかります。

`x.b`のオフセットは8バイトで先頭から8バイトのフィールド`a`の直後からデータが格納されていることがわかります。

そして`x.c`のオフセットは16バイトなので先頭から8バイトのフィールド`b`の直後からデータが格納されていることがわかります。

先頭アドレスからオフセットだけ後ろの場所を見ることでフィールドのメモリ位置を特定することができます。

### コピー代入

変数に値を代入する時は必ずコピーが作成されています。

実際に見ていくと

```go
package main

import "fmt"

type X struct {
	s string
}

func main() {
	var x1 X
	x2 := x1
	fmt.Printf("x1: %p\n", &x1)
	fmt.Printf("x2: %p\n", &x2)
}
```

上記の実装では、`var x1 X` で型Xの変数`x1`を定義しその後`x2 := x1`で`x2`に代入しています。

実際に実行してみると、

```go
x1: 0x14000010070
x2: 0x14000010080
```

`x1`と`x2`はそれぞれアドレスが異なります。

これは`x1`と`x2`はそれぞれ別のメモリ領域にあることを示しています。

図で見ていくと、

`var x1 X` でx1で使うためにXの型サイズである8バイト分メモリを確保します。

![スクリーンショット 2024-07-21 18.03.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/b708d971-587e-de0d-85ae-ee0b1d5e18d4.png)


その後`x2 := x1` での代入で`x2`で使うためにx1とは別の領域に8バイトを確保しています。

別の領域にデータを確保したので`x2`は`x1`の先頭アドレスと異なります。

![スクリーンショット 2024-07-21 18.05.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/75edcd68-d064-ab5c-515e-db00986b1fd1.png)


次に、`x1`の8バイト分の値を`x2`の8バイト領域にコピーした結果両者の8バイト分のビットの並びは同じになります。

![スクリーンショット 2024-07-21 18.07.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/21952992-30e7-82c4-4628-28a40ce06c7c.png)


この結果、`x1`と`x2`は同じ値ですがアドレスが違う状態になります。

つまり`x2`に`x1`のコピーが代入されました。このフローを**コピー代入**と呼びます。

コピー代入はどの型でも起こります。

### 直接参照と間接参照

前提知識として**型サイズ**、**オフセット**、**コピー代入**について解説したのでいよいよ本題です。

直接参照と間接参照とはメモリ上のデータにアクセスする方法の違いです。

**ポインタ型の指定**

Goでは`%T` を使うことで変数の型が分かります。

以下のコード例ではmainパッケージの型`X`と型`*X`になる変数を作っています。

```go
package main

import "fmt"

type X struct {
	s string
}

func main() {
	x1 := X{}
	x2 := new(X)
	var x3 X
	var x4 *X
	fmt.Printf("x1: %T\n", x1)
	fmt.Printf("x2: %T\n", x2)
	fmt.Printf("x3: %T\n", x3)
	fmt.Printf("x4: %T\n", x4)
}
```

実行結果

```go
x1: main.X
x2: *main.X
x3: main.X
x4: *main.X
```

通常型とポインタ型は全く別の型と説明しましたが、実際は**通常型は直接参照**、**ポインタ型は間接参照**を使ってデータにアクセスするという決まりがあります。

通常の型かポインタ型かどうかというのはコード上で直接参照を使うのか間接参照を使うのかを明示しているわけです。

**ポインタ渡し**

続いて関数のポインタ渡しについてです。

関数のポインタ渡しとはポインタ型の引数を受け取る関数を定義してその関数にアドレスを渡すことです。

つまり関数がポインタ型の引数を受け取るのであれば必然的にポインタ渡しになるわけです。

以下のコードは型`*X`の引数を受け取る関数`test`を定義し実引数`x1`と仮引数`x2`の値とアドレスを出力しています。

```go
package main

import "fmt"

type X struct {
	s string
}

func test(x2 *X) {
	fmt.Printf("x2 value: %p\n", x2)
	fmt.Printf("x2 address: %p\n", &x2)
}

func main() {
	x1 := new(X)
	fmt.Printf("x1 value: %p\n", x1)
	fmt.Printf("x1 address: %p\n", &x1)
	test(x1)
}
```

実行結果

```go
x1 value: 0x1400008e020
x1 address: 0x140000a2018
x2 value: 0x1400008e020
x2 address: 0x140000a2028
```

`x1`と`x2`の型はどちらも`*X`なのでアドレスの値が入ります。また`*X`はポインタ型なので構造体`X`のサイズに関係なく8バイトです。値（`value`）は同じですがアドレスは別の値になります。

**データへのアクセス**

直接参照と間接参照の違いはデータにアクセスするステップが異なることです。

この違いにより値の代入なのか参照の代入なのかを説明することができます。

**直接参照の場合**

以下のコードは直接参照でデータにアクセスする例です。

```go
package main

import (
	"fmt"
	"unsafe"
)

type X struct {
	i int
	f float64
}

func main() {
	x1 := X{}
	x1.f = 1.5
	fmt.Printf("x1.f: %f\n", x1.f)
	fmt.Printf("x1 address: %p\n", &x1)
	fmt.Printf("x1 size: %d\n", unsafe.Sizeof(x1))
}
```

intとfloat64のフィールドを持ち型サイズが16バイトの構造体Xを定義しました。

`x1 := X{}`で`x1`にインスタンスを代入し`x1.f = 1.5`で`x1.f`を書き換え`x1`のフィールド`f`とポインタ型とサイズを出力しています。

実行結果

```go
x1.f: 1.500000
x1 address: 0x140000a4020
x1 size: 16
```

図を使ってメモリ内の状態を見ていきます。

まず`x1 := X{}` では`x1`のメモリ領域を確保し構造体Xの値を代入します。

アドレス`0x140000a4020` を先頭に16バイト分のメモリを使用します。

![スクリーンショット 2024-07-21 18.12.26.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/e2d8ed06-f871-3669-7b5e-7050b0ef3c21.png)


続いて`x1.f = 1.5` でオフセットが8バイトのフィールドfの値を書き換えます。

`x1`の先頭アドレスから8バイトオフセットした位置を起点としてfloat64の型サイズである8バイトの領域にデータを書き込んでいます。

![スクリーンショット 2024-07-21 18.15.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/9936cc28-bb38-4c65-44a4-4db50f6c3d41.png)


そして`fmt.Printf("x1.f: %f\n", x1.f)` では上記の書き込みと同様に`x1`の先頭アドレスから8バイトオフセットした位置を起点として8バイトの領域のデータを読み込んでいます。

**間接参照の場合**

次に間接参照でデータにアクセスする例です。

```go
package main

import (
	"fmt"
	"unsafe"
)

type X struct {
	i int
	f float64
}

func main() {
	x2 := new(X)
	x2.f = 1.5
	fmt.Printf("x2.f: %f\n", x2.f)
	fmt.Printf("x2 address: %p\n", &x2)
	fmt.Printf("x2 value: %p\n", x2)
	fmt.Printf("x2 size: %d\n", unsafe.Sizeof(*x2))
}
```

今回は構造体`X`のポインタ型である`*X`の変数`x2`を定義しました。

実行結果

```go
x2.f: 1.500000
x2 address: 0x14000116018
x2 value: 0x14000110020
x2 size: 16
```

先ほど同様に図でメモリ内の状態を見ていきます。

まず`x2 := new(X)`で`x2`の8バイトのメモリ領域を確保します。

次に構造体`X`のサイズの16バイトのメモリ領域を確保し先頭のアドレスの値（`0x14000116018`）を`x2`の値に入れます。

![スクリーンショット 2024-07-21 18.20.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/80605559-5cc1-33e5-0aba-8268611807f5.png)


続いて`x2.f = 1.5`で`x2`で値として保持しているアドレスを先頭アドレスとしそこから8バイトオフセットしたメモリのアドレスを起点とする`float`型のサイズの8バイトをメモリ領域に書き込みます

![スクリーンショット 2024-07-21 18.22.30.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/3fbf67dc-e095-6e7e-ca1d-22c64c381463.png)


`fmt.Printf("x2.f: %f\n", x2.f)`でメモリ上のデータを読み込むときは`x2.f = 1.5` と同様にx2で値として保持しているアドレスを先頭にし8バイトオフセットしたメモリのアドレスを起点として8バイトのデータ領域を読み込んでいます。

間接参照の場合は直接参照と違い一度変数に入っているアドレスの値を読み込みそのアドレスを先頭アドレスとする型サイズの領域のデータの読み書きをしています。

つまり直接データを読み書きするのではなく一度アドレスの値を経由して間接的にデータの読み書きを行なっているわけです。

ポインタ型を使うと、変数にアドレスをコピーして同じメモリ領域を共有できます。これは、アドレスの値が同じため、間接参照で同じデータにアクセスするからです。

# 変数とアドレスの関係

色々ポインタについて説明してきましたがここでようやく最初のコードに戻ります。

```go
package main

import "fmt"

type Item struct {
	value string
}

func main() {
	items := []Item{{value: "A"}, {value: "B"}, {value: "C"}}
	pointerList := make([]*Item, 0, len(items))

	for _, i := range items {
		pointerList = append(pointerList, &i)
	}

	for _, p := range pointerList {
		fmt.Println(p.value)
	}
}
```

```go
// 期待する実行結果 
A
B
C
// 実際の実行結果 
C
C
C
```

なぜこのような結果になってしまうのか、まずは`pointerList`に格納されたアドレスの値を見ていきます。

```go
package main

import "fmt"

type Item struct {
	value string
}

func main() {
	items := []Item{{value: "A"}, {value: "B"}, {value: "C"}}
	pointerList := make([]*Item, 0, len(items))

	for _, i := range items {
		pointerList = append(pointerList, &i)
	}

	for i := range pointerList {
		fmt.Printf("%p\n", pointerList[i])
	}
}
```

実行結果

```go
0x1400008e040
0x1400008e040
0x1400008e040
```

実行結果を見ると`pointerList`の要素にはすべて同じアドレスが入っていることがわかります。

同じアドレスなので同じフィールドの値が出力されていたわけです。

もう少し具体的に見ていくために`for`文を分解してみます。

```go
package main

import "fmt"

type Item struct {
	value string
}

func main() {
	items := []Item{{value: "A"}, {value: "B"}, {value: "C"}}
	pointerList := make([]*Item, 0, len(items))

	var i Item                            // ①

	i = items[0]　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　　// ②
	pointerList = append(pointerList, &i)　　// ③

	i = items[1]                          //　④
	pointerList = append(pointerList, &i) //　⑤

	i = items[2]                          //　⑥
	pointerList = append(pointerList, &i) //　⑦

	for _, p := range pointerList {
		fmt.Println(p.value)
	}
}
```

`for` 文の変数`i`は①にあるように一度定義されていて②、④、⑥で`pointerList`の要素がコピー代入されています。

そして③、⑤、⑦で`pointerList` に`i`のアドレスが要素として追加されています。

メモリ内の状態を順番に見ていきます。

以下は①が実行された時点でのメモリ内を表した図です。

![スクリーンショット 2024-07-21 18.38.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/57e9f673-e1b3-dfd9-a213-c253967b783b.png)


変数`i`のメモリ領域（図左）とsliceである`items`のメモリ領域（図右）が確保されています。

`items`の要素数は3なのでサイズ3つ分のメモリが確保されています。

データ領域は各要素ごとに区切られているのでそれぞれに先頭アドレスが存在します。

次に②が実行された時点の図です。

![スクリーンショット 2024-07-21 18.38.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/486ed4e6-9054-b0bf-fa2a-937d99c0a89c.png)


`i`に`items[0]`の値を代入したので`i`と`items`は同じ値になっています。

しかし先頭のアドレスは値が異なります。

③が実行された時点の図です。

![スクリーンショット 2024-07-21 18.37.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/10348fda-b7a3-7fe6-4b1e-3944f1b5f0a4.png)


`i`の領域の先頭アドレスを`pointerList`の要素に追加します。ここで`*item`型の`pointerList` に格納されるのはiの先頭アドレスであって`items[0]` の先頭アドレスではありません。

これ以降はitemsの要素に対して同様の処理が繰り返されます。

最後の⑦が実行された時点の図は以下です。

![スクリーンショット 2024-07-21 18.41.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/aa9e15d1-66c6-05e2-b7b4-70d043b43b7b.png)


⑦が実行されたとき`i`の値は`items[2]`の値が代入されています。

`pointerList`の全ての要素には`i`の先頭アドレスが入っていてこの状態で⑧を実行すると実際の実行結果であるすべて`C`が出力されます。

### 正しい実装

それでは最後に期待通りの結果を得るための正しい実装をしていきます。

```go
package main

import "fmt"

type Item struct {
	value string
}

func main() {
	items := []Item{{value: "A"}, {value: "B"}, {value: "C"}}
	pointerList := make([]*Item, 0, len(items))

	for i := range items {
		pointerList = append(pointerList, &items[i])
	}

	for _, p := range pointerList {
		fmt.Println(p.value)
	}
}
```

実行結果

```go
A
B
C
```

インデックスで要素を指定してそのアドレスを取得するだけで要素の先頭のアドレスを`pointerList`に格納することができます。

![スクリーンショット 2024-07-21 18.47.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/48a53d57-732e-23a2-017a-383bc78f0db2.png)


# まとめ

今まで脳死で使っていたポインタですが今回改めてポインタの概念について深掘りしてみて思ったのはポインタを扱う際は**どの領域の先頭アドレスを指しているのかきちんと把握する必要がある**ということです。

ただ今回のようなシンプルな実装ではまだ意識することができますが実際のサービスに使われているような複雑なコードだとどうしても見落としてしまうなとも思いました。

悩んだら一度立ち止まり今回作った図などを頭の中で作る癖をつけたいなと思いました。

## 参考

- https://techbookfest.org/product/5039923363053568?productVariantID=5673208908873728
- https://qiita.com/Sekky0905/items/447efa04a95e3fec217f
- https://go-tour-jp.appspot.com/moretypes/1