問題
2つの数字を入れ替えるswap関数を実装します。
swap関数の引数として、2つの数字のメモリアドレスが渡されるものとします。
package main
import "fmt"
func main() {
num1, num2 := 1, 2
swap(&num1, &num2)
fmt.Println(num1, num2) // 2, 1
}
本記事ではポインタそのものに関する解説はしません。
ポインタに関しては以下の記事が参考になります。
誤答
私が最初に考えた答えは以下の通りです。何が誤りなのか考えてみてください。
func swap(a, b *int) (a2, b2 *int) {
a2, b2 = b, a
return
}
誤っている点
1. 返り値がある
swap(&num1, &num2)
のように呼び出しており返り値を受け取る形式ではないのに、返り値としてx2
, y2
を返してしまっています。
2. ポインタを使用していない
swap関数の引数として与えられたa
, b
に格納されているのは、メモリアドレス(値が格納されている場所)のコピーにすぎません。
なのでa2, b2 = b, a
としても、a2
, b2
にb
, a
の値を代入しているだけで、元の値が変更されるわけではありません。
元の値を変更するにはポインタを使用する必要があります。
簡単な例を挙げます。
package main
import "fmt"
func modify(ptr *int) {
// *ptrはポインタなので変更される
*ptr = 100
// ptrはコピーされた値なので、メモリアドレスは変更されない
ptr = nil
}
func main() {
x := 10
ptr := &x
fmt.Printf("ptr:%v, *ptr:%v\n", ptr, *ptr) // ptr:0xc0010e010, *ptr:10
modify(ptr)
fmt.Printf("ptr:%v, *ptr:%v\n", ptr, *ptr) // ptr:0xc0010e010, *ptr:100
}
正答
以上を踏まえて、正しい答えは以下の通りです。
*a, *b = *b, *a
とすることで、コピーされたメモリアドレスではなく、ポインタが指す実際の値を変更できます。
func swap(a, b *int) {
*a, *b = *b, *a
return
}