参照渡しと値渡し

# 参照渡しと値渡し

go言語を勉強し始めてから久しぶりにポインタを利用することになったので改めてポインタやらアドレスやらのややこしいとこを自分なりに見直しました．


## 値渡し

go言語の場合

```person.go
package main

import "fmt"

type Person struct {
	Name string
	age int
}

func growUp(person Person) {
	person.age++
	fmt.Println("innerFunc", person.age)
}

func main() {
	var person Person
	person.Name = "とくまる"
	person.age = 20
	fmt.Println("before", person.age)
	growUp(person) // 1コ歳をとらせる
	fmt.Println("before", person.age)
}
```

このプログラムを実行してみます

```terminal
% go run person.go
before 20 // 関数実行前
innerFunc 21 // 関数内での出力
after 20 // 関数実行後のmain()内での出力
```

出力結果は上記のようになり，関数内では年齢が１コ増えてますが，afterの出力を見てわかるように関数に渡した`person`の値は変わっていません！これが値渡しで，`person`のコピーを作って関数に渡しているような感じです

## 参照渡し

次に参照渡し

``` person.go
package main

import (
	"fmt"
)

type Person struct {
	Name string
	age int
}

func growUp(person Person) {
	person.age++
	fmt.Println("innerFunc:", person.age)
}

//変更点/////////////////////////////////
func fixGrowUp(person *Person) {
	person.age++
	fmt.Println("innerFunc:", person.age)
}
/////////////////////////////////////////


func main() {
	//var person Person
	person := &Person{}
	person.Name = "とくまる"
	person.age = 20
	fmt.Println("before:", person.age)
	//growUp(person)
	fixGrowUp(person)
	fmt.Println("after:", person.age)
}
```

新しく`fixGrowUp`という関数を作りました．出力結果は以下のようになります．

``` terminal
% go run person.go
before: 20 // 関数実行前
innerFunc: 21 // 関数内での出力
after: 21 // 関数実行後のmain()内での出力
```

今度は関数実行後の出力も歳をとっています．これが参照渡しです．アドレスのポインタ渡して，関数に渡した`person`を書き換えてます．

## いや

知ってたでって感じの人が多いと思いますが，C言語に挫折し，pythonやらjavascriptやらでポインタとおさらばしてなんとなくプログラミングしてたらすっかり気にしなくなってました。（笑）

## Pythonでは？

**ここからが本題**です！

前置きが長くなりましたが，伝えたかったのはここからです．参照渡しとかほとんど意識せずプログラム書いてたけどpythonだとどうなってるの？って思って調べてみました．

#### pythonは全て参照渡し

らしいです．そして，書き換わる型と書き変わらない型があるらしいです．以下を見てください．


```person.py
def change_int(age):
    age = 21

def main():
    age = 20
    data = {"name": "とくまる", "age": 20}
		print("type", type(age))
		print("before: ", age)
		change_int(age)
    print("after: ", age)

main()
```

```terminal
% python person.py
type <class 'int'>
before:  20
innerFunc 20
after:  21
```


これは，int型の`age`を書き換えたものですがpythonは全て参照渡ししてるのに書き換わってないですね．参照渡しするけど「書き換えるならコピーして元のと別のやつ書き換えるよ」みたいな？次にdict型

```person.py
def change_int(age):
    age = 21
    print("innerFunc", age)

################変更点###########################
def change_dict(person):
    person["age"] = 21
    print("innerFunc", person["age"])
##################################################
def main():
    age = 20
    person = {"name": "とくまる", "age": 20}
    print("type", type(person))
    print("before: ", person["age"])
    # change_int(age)
    change_dict(person)
    print("after: ", person["age"])

main()
```

今度はdict型の中の変数を書き換える関数を書きました．出力結果は以下のようになります．

```terminal
% python person.py
type <class 'dict'>
before:  20
innerFunc 21
after:  21
```

書き換わってますね．dict型は書き換えちゃうみたいですね．書き換わるやつ(mutable)と書き変わらんやつ(immutable)は以下のようになっています．

- 書き換えできない型
	- int, float, str, tuple, bytes, frozenset ..
- 書き換え可能な型
	- list, dict, set, bytearray ..

なんとなくpythonが簡単だからと思ってプログラミングしてる方は以上のことを意識してプログラミングしていきましょう！


## おまけ

listがmutableだから

```python

def implement(awesome_list):
	for elem in awesome_list:
		elem += 1
def main():
	awesome_list = [1, 2, 3] # intのリスト
	implement(awesome_list)
	print(awesome_list)
```

上記のようにして書き換えたくなりますが，ここで生成される`elem`は`awesome_list`の要素のコピーなので，

```python
	elem += 1
```
では要素のコピーを書き換えてることになります．したがって，main()での出力結果は`1, 2, 3`のままです．解決方法としては

1. 関数内で新しい空のリストを定義して，for文の中でappendする
2. リストの要素に直接アクセスする

```
	for i in range(len(awesome_list)):
		awesome_list[i] += 1
```

まあざっくりと，(1)「新しいリスト作って書き換えた要素追加する」か，(2)「リストの要素の番号指定してちまちまアクセスして書き換えてく」かって感じですかね個人的に(2)だとpythonのよさみたいなものが消えてるような気がするので(1)をおすすめします

**＊ ここではリストの要素がint型(immutable)なので書き換えれませんでしたが，リストの要素がmutableの場合は書き換え可能です！**

新しい言語を始める際のチェックポイントとして「値渡しと参照渡し」のルールについてその言語ではどうなってるのかっていうのはチェックしておくと**スムーズ**に**正確**にプログラミングできると思います！