AOJやっててハマったので
package main import ( "fmt" ) type Element struct { number int } func main() { Elementのsliceの場合() Elementのポインタのsliceの場合() } func Elementのsliceの場合() { elements := []Element{} for i := 0; i < 2; i++ { elements = append(elements, Element{i}) } fmt.Println(elements) // 0 1 elements[0].number = 10 fmt.Println(elements) // 10 1 // これは99にならない for _, elem := range elements { elem.number = 99 } fmt.Println(elements) // 10 1 // これは99になる for i := 0; i < 2; i++ { elements[i].number = 99 } fmt.Println(elements) // 99 99 } func Elementのポインタのsliceの場合() { elements := []*Element{} for i := 0; i < 2; i++ { elements = append(elements, &Element{i}) } fmt.Println(elements) // 0 1 // これは99になる for _, elem := range elements { elem.number = 99 } fmt.Printf("%v %v\n", elements[0].number, elements[1].number) }
rangeで返ってくる値は要素のコピーになる(=参照が別)のかなと思ってポインタを見てみた感じ、そうっぽい
package main import ( "fmt" ) type Element struct { number int } func main() { Elementのsliceの場合のポインタ() Elementのポインタのsliceの場合のポインタ() } func Elementのsliceの場合のポインタ() { elements := []Element{} for i := 0; i < 2; i++ { elements = append(elements, Element{i}) } fmt.Println("各要素のポインタ:") fmt.Printf("element[0] pointer:%p\n", &elements[0]) fmt.Printf("element[1] pointer:%p\n", &elements[1]) fmt.Println("rangeの場合のポインタ:") for _, elem := range elements { // このポインタは&elements[0]とも&elements[1]とも異なる // さらに、ループ内で&elemはどの要素に対するポインタも同じ fmt.Printf("element[%v]] pointer:%p\n", elem.number, &elem) } } func Elementのポインタのsliceの場合のポインタ() { elements := []*Element{} for i := 0; i < 2; i++ { elements = append(elements, &Element{i}) } fmt.Println("各要素のポインタ:") fmt.Printf("element[0] pointer:%p\n", &elements[0]) fmt.Printf("element[1] pointer:%p\n", &elements[1]) for _, elem := range elements { // このポインタは&elements[0]とも&elements[1]と等しい fmt.Printf("element[%v]] pointer:%p\n", elem.number, elem) // ループ内で&elemはどの要素に対するポインタも同じ(ポインタのポインタになってるはず) fmt.Printf("element[%v]] pointer:%p\n", elem.number, &elem) } }
と思ったらtour of goにも書いてあった https://tour.golang.org/moretypes/16
When ranging over a slice, two values are returned for each iteration. The first is the index, and the second is a copy of the element at that index.
channelも同じような感じ
package main import "fmt" type Element struct { number int } func send(c chan Element) { for i := 0; i < 3; i++ { elem := Element{i} fmt.Printf("send: %p\n", &elem) c <- elem } close(c) } // send: 0xc000094008 // send: 0xc000094018 // range: 0xc000094000 // range: 0xc000094000 // send: 0xc000018058 // range: 0xc000094000 func main() { c := make(chan Element) go send(c) for val := range c { fmt.Printf("range: %p\n", &val) } }
関数に渡した場合にコピーになる奴でもちょっとハマったんだよな
どうするか
- インデックスでループしてインデックスでアクセス
- rangeでループしてインデックスでアクセス
- ポインタの配列にする
あたり?