ポインタが分からない②
ポインタのことがやっぱり分からない。
どうしても納得いかないので、もうちょっと良く考えてみることにした。
以下のサンプルコードを動かして色々試してみると、どうも難しく考えるからいけないんだと思うようになった。
単なるルールとして、「ポインタを使うと同じものを指す」とだけ覚えておけば別に困らない気がしてきた。
package main import ( "fmt" ) type Point struct { x int y int } func main() { var p = &Point{10, 20} var P = Point{3, 6} // これは、qがpそのものであることを直感的に示している。 q := p // こちらも、(PとQは別物であることを前提に)、QがPそのものを指し示すよう指示しているように見える。 Q := &P // これは、rとpが異なるものであることを直感的に示している。 r := *p // ところが、これが、R !== P であることがわからない。 R := P // つまり、この式でR === Pであるという前提を暗に抱いているといえる。 // よって、「ポインタを代入しない限り、別物」から考え始めるのが良い。 // sにはqのポインタを代入するので、s === q であることに疑いはない。 s := &q // これは、p自体を操作しているようにしか見えない。 (*p).x = 12 S := *p; S.x = -100 // これをやってもpは一切影響を受けない。 // これもまた、P自体を操作しているようにしか見えない。 (&P).x = 45 r.y = 17 // rにはポインタを取らなかったので、ここでpは影響を受けない。 fmt.Println(p, q, r, *s) // &{12 20} &{12 20} {10 17} &{12 20} fmt.Println(P, Q, R) // {45 6} &{45 6} {3 6} }
どうもわたしが理解できていなかったことは、
- &や*を付けると同じものや違うものを指すと誤解していた
- そうではなくて、代入すると別々に分けられるタイミングが来るようだ
- しかし、アドレス演算子を使ってポインタを代入すると、左辺と右辺が同一であることを示せる
- (*p)や(&P)を使ってある変数そのものを操作できることから、やっぱり演算子自体にオブジェクトを分別する役割は無くて、代入に起因するとしか思えない。
ここまで考えるうちにつらくなってきて、要は「ポインタを使うと同じものを指す」とだけ覚えておけば良いんじゃないかと思うようになった。
元々、変数をポインタ型で宣言してしまうと、今度は「それ自身」を取り出す術がなくなるので、「*」という演算子が用意されている、と。
(まだよくわかってない・・)