go言語を扱うときはrangeに気を付けろ

1 min read読了の目安(約1000字

TL;DR

結論からいうとrange{}の中の一時変数はあくまで一時変数なので、元々の配列には何も入らないことに気をつけてください。

i, u := range users{
	u = User{}        //uは値渡しであり、元々のusersには何も入らないのでダメ
	users[i] = User{} //iにはusersのインデックスが入っているのでそこに代入する 
}

僕はこれに気づかず、一時間以上悩んでしまったので気をつけてください。。。

起こってたこと

基本の話ですが、go言語の利便さからチャチャっと書いたコードで一時間くらい悩まされたので記事を書きます。

まず、この様にネストされている二つの構造体があります

type User struct{
	id int
	profile Profile

}

type Profile struct{
	zenn string
}

そして、以下のコードを定義したとします。


func main() {
	users := []User{
		User{},
		User{},
		User{},
	}
	
	_, u := range users{
		u.profile.zenn = "zenn is awesome!"
	}
	
	
	log.Printf("%#v", users)

}

するとどうなるでしょう?
go言語を日頃から扱ってる方は「そりゃだめだろ!」というと思いますが、、、
usersのそれぞれのuserの中のprofileには何も入っていません

僕はこれに一時間以上悩みました。なんか動かねえ!!!!!
これの悪いところは見た目では正しいコードに見えるんですよね。おかしそうに見えない。

何がダメなのか

先ほどのコードで、一時変数であるuに代入しているのが問題ですね。
uは値渡しなので、users{}の値は関係ないです。

よくよく考えたら、phpのforeachや、javaの拡張forなどもそうなのですが、基本foreachはその配列の中の要素全てを一つづつ処理したり、計算にしようしたりと、代入目的ではあまり使わないですよね。
言われてみたらPHPを使ってた時もそんな感じだった!!と思いました。
プログラムの基本文法がなってなかった。。。。

以上です。