Go言語で理解する値渡しと参照渡し

### はじめに
Go言語での値渡しと参照渡しについて、基本的なデータ型、ポインタ、構造体、スライスの振る舞いを用いたサンプルコードを解説していきます。
値渡しと参照渡しの概念を確認していきます。

### 基本データ型の場合

#### 値渡し
```go
package main

import "fmt"

func updateValue(x int) {
    x = x + 1
}

func main() {
    a := 10
    fmt.Println("Before updateValue:", a) // 10
    updateValue(a)
    fmt.Println("After updateValue:", a) // 10 (aは変わらない)
}
```
このコードでは、整数型の変数aの値を`updateValue`関数に渡しています。渡された引数`x`は値渡しのため、関数内で`x`の値を変更しても、元の変数`a`の値に影響を与えません。`updateValue`関数内で`x`に1を加算しても、元の変数aの値は10のままです。


#### 参照渡し
```go
package main

import "fmt"

func updateValue(x *int) {
    *x = *x + 1
}

func main() {
    a := 10
    fmt.Println("Before updateValue:", a) // 10
    updateValue(&a)
    fmt.Println("After updateValue:", a) // 11 (aが更新される)
}
```
このコードでは、整数型の変数`a`のアドレスを`updateValue`関数に渡しています。引数`x`の型を`*int`に変更して、ポインタ型を受け取れるようにしました。`&a`は変数`a`のアドレスを表し、関数内で引数xを介して元の変数`a`を参照・変更することができます。
`updateValue`関数内で`*x`に1を加算すると、`*x`は元の変数aを指しているため、変数`a`の値が更新されます。

### 構造体

#### 値渡しのような振る舞い
```go
package main

import "fmt"

type Student struct {
    Name string
    Age  int
}

func updateStudent(s Student) {
    s.Age = s.Age + 1
}

func main() {
    student := Student{Name: "Taro", Age: 16}
    fmt.Println("Before updateStudent:", student) // {Taro 16}
    updateStudent(student)
    fmt.Println("After updateStudent:", student) // {Taro 16} (student.Ageは変わらない)
}
```
このコードでは、構造体`Student`が定義され、それを引数として`updateStudent`関数に渡しています。`Student`構造体は値渡しのような振る舞いをします。つまり、`updateStudent`関数内で引数`s`の値（`s.Age`）を変更しても、元の`student`構造体の値に影響を与えません。この例では、`updateStudent`関数内で`student.Age`に1を加算しても、元の`student.Age`の値は変わらないことがわかります。

#### 参照渡し
```go
package main

import "fmt"

type Student struct {
    Name string
    Age  int
}

func updateStudent(s *Student) {
    s.Age = s.Age + 1
}

func main() {
    student := Student{Name: "Taro", Age: 16}
    fmt.Println("Before updateStudent:", student) // {Taro 16}
    updateStudent(&student)
    fmt.Println("After updateStudent:", student) // {Taro 17} (student.Ageが更新される)
}
```
このコードでは、構造体`Student`のポインタを引数として`updateStudent`関数に渡しています。引数`s`の型を`*Student`に変更して、ポインタ型を受け取れるようにしました。`&student`は変数`student`のアドレスを表し、関数内で引数`s`を介して元の`student`構造体を参照・変更することができます。

`updateStudent`関数内で*sの値（`s.Age`）に1を加算すると、`*s`は元の構造体`student`を指しているため、`student.Age`の値が更新されます。この例では、Go言語の参照渡しを構造体のポインタを使って実現しており、関数内で引数の値を変更することができることを示しています。

### スライス

#### 振る舞い
```go
package main

import "fmt"

func updateSlice(s []int) {
    s[0] = 100 // 要素を変更
    s = append(s, 200) // スライス自体を変更
}

func main() {
    nums := []int{1, 2, 3}
    fmt.Println("Before updateSlice:", nums) // [1 2 3]
    updateSlice(nums)
    fmt.Println("After updateSlice:", nums) // [100 2 3] (要素は変更されるが、追加された要素は反映されない)
}
```
このコードでは、スライス`nums`を`updateSlice`関数に渡しています。スライスは、配列への参照を保持しており、スライスを関数に渡すときは参照渡しのような振る舞いをします。ただし、スライスの要素に対する変更と、スライス自体への変更は異なります。

`updateSlice`関数内で、引数sの要素（`s[0]`）を変更すると、元のスライス`nums`の要素も変更されます。しかし、関数内でスライス自体を変更する操作（`append`関数で要素を追加する）を行うと、元のスライス`nums`には反映されません。これは、スライスが別のメモリ領域（新しい配列）を参照するようになるためです。

この例では、スライスを関数に渡すと、要素の変更は元のスライスに影響を与えるが、スライス自体の変更（要素の追加や削除など）は元のスライスに影響を与えないことがわかります。

### まとめ
この記事では、Go言語の値渡しと参照渡しについて、基本的なデータ型、ポインタ、構造体、スライスの振る舞いを用いたサンプルコードを解説しました。これらのサンプルコードを通して、以下の点について理解が深まることを目指しました。

1. 基本的なデータ型は値渡しで、関数内で変更しても元の変数に影響がない。
2. ポインタを使って参照渡しを実現し、関数内で変更すると元の変数も変更される。
3. 構造体やスライスは内部的には参照渡しですが、その振る舞いは値渡しに似ている。
4. 構造体をポインタで渡すことで参照渡しを実現し、関数内で変更すると元の構造体も変更される。
5. スライスの要素を変更すると、元のスライスに影響がありますが、スライス自体を変更（要素の追加や削除）すると元のスライスには影響がありません。

これらの概念を理解することで、Go言語での関数呼び出しやデータの受け渡しについて効果的なコードを書くことができます。値渡しと参照渡しの使い分けにより、必要に応じてメモリの効率やデータの変更の影響範囲をコントロールすることが可能になります。

https://stackoverflow.com/questions/71249224/difference-between-pass-by-value-and-pass-by-reference