実行環境

  • go(ver. 1.18.3)
  • M1 Macbook Air (late 2020)

概要


今回の記事では、いくつかのプログラミング言語で初心者が難しいとよく感じるであろうポインタの仕組みと使い方についてまとめました。そして、特に今回は簡素で効率的な開発ができるGo言語におけるポインタについて取り上げます。


ポインタ とは

そもそもポインタとは何なのかみなさんはご存知でしょうか。Wikipediaの当該記事によると、

ポインタとは、コンピュータプログラミングにおいて、変数や関数などが置かれたメインメモリ上の番地(メモリアドレス)などを格納する特殊な変数のこと。あるオブジェクトがなんらかの論理的位置情報に基づいてアクセスできるとき、それを参照する(指し示す)ものである。一般的な意味での「ポインタ」は「何かの位置を指し示すための仕組みや道具」のことであり、転じてコンピュータプログラミングの分野でも利用されるようになった。 と説明されています。上記の説明にもあるように、一般的なポインタとは「何かの位置を指し示すための仕組みや道具」としての役割をプログラミングの分野でも持っているということがわかります。

なぜポインタが必要か?

それでは、なぜ一部の言語ではポインタが必要なのでしょうか?そこには、ポインタを使うことで便利な点がいくつかあるためです。主な点は以下の2つです。

  1. プログラムの高速化
  2. コードの設計の簡素化

1つ目の「プログラムの高速化」についてですが、これは端的に言うとポインタを用いることで構造体などのオブジェクトのコピーのコストが減るためです。

2つ目の「コードの設計の簡素化」については、プログラミングにおいて多様される変数のメモリアドレスを共有できるためにコード設計がシンプルになります。

Go言語におけるポインタの使い方

Go 言語におけるポインタの使い方について説明します。先ほども述べてきたように、ポインタとはメモリアドレスを指し示すものを意味するものでした。つまり、ポインタを用いるには、まずはメモリアドレスをどこかに格納する機能が必要です。しかし、変数をメモリアドレスとして格納するだけでは、それ自体を他の関数内で解読することができません。よって、アドレスを値として入れられる機能も必要となります。上記の2つの機能を持っているのが「ポインタ」と「ポインタ変数」と呼ばれるものになります。これら2つは以下のようにGo言語上で表せます。

  1. ポインタ: &p(= 渡したい変数)
  2. ポインタ変数: *v(= 渡したい変数の型)

これら2つを用いることで、ポインタを用いることができます。

実例

それでは、実際にGo言語でどのようにポインタが使われているのか見てみましょう。

package main
import (
    "fmt"
)
func double(number *int) {
    *number *= 2
}
func main() {
    amount := 6
    double(&amount)    
    fmt.Println(amount)
}

上記のコードは、main 関数内でamount という変数名で整数型の変数を受け取って、double 関数にその変数を引数として渡すことで、2倍の整数を計算し、出力するものになっています。ここで、main 関数内の double(&amount)&amountという変数のアドレスを一時的に保存しています。これにより、amountという変数のポインタ型を生成することができます。

また、double 関数内のdouble(number *int)*intはint 型のポインタをnumberという引数の型として定義しています。そして、double関数内の*numberもポインタ型として定義されており、計算結果がnumberという引数に記録されます。main 関数内では引数はamountとして渡されています。よって、amountのアドレスにdouble関数の計算結果のアドレスが格納されます。

このようにして、変数amountdouble関数内で計算し、正しく出力することができます。