プログラミングでは、変数の扱い方がプロジェクトの成功を左右します。
特に、Swiftのような言語でソフトウェアを開発する際、値渡しと参照渡しの違いを理解することは不可欠です。
あなたは、関数に変数を渡すとき、その変数の「本物」を渡しているのか、それともただの「コピー」を渡しているのか、その違いがプログラムにどのような影響を与えるかを考えたことがありますか?
この記事では、値渡しと参照渡しの概念を明確にし、Swiftでこれらの概念をいかに駆使して効率的かつエラーのないコードを書くかを、サンプルコードを用いて解説します。
さらに、PCのファイル操作に例えて直感的に理解できるようにも導きます。
あなたのSwiftプログラミングスキルを次のレベルに引き上げるための知識を、わかりやすく解説していきます。
値渡し
値渡しサンプルコード
func nameFunc1(name1: String) {
let name1 = "初期値"
print(name1)
}
var res1 = "変更値"
print(res1)
nameFunc1(name1: res1)
print(res1)
結果
変更値
初期値
変更値
プログラムの実行順序に解説
- 6行目
変数res1が宣言されて、res1に”変更値”が代入(初期化)されます。 - 7行目
コンソールにrest1の値”変更値”が出力 - 8行目
nameFunc1(name1: res1)が関数func nameFunc1(name1: String) を呼び出します。 - 8行目、1行目
8行目のrest1の値”変更値”が1行目のname1に渡されて、1行目のname1の値は”変更値”になります。(値渡し)
渡されるとは代入またはコピーされるという意味です。 - 2行目
関数内にある定数name1が宣言されて、name1に”初期値”を代入
ここで注意すべき2行目のname1と8行目のname1はスコープが異なるため別物です。
2行目のname1の値は”初期値“で8行目のname1の値は”変更値”です。
メモリー上のアドレスが違うと考えて下さい。 - コンソールにrest1の値”変更値”が出力
参照渡し
参照渡しサンプルコード
func nameFunc2(name2: inout String) {
name2 = "初期値"
print(name2)
}
var res2 = "変更値"
print(res2)
nameFunc2(name2: &res2)
print(res2)
結果
変更値
初期値
初期値
プログラムの実行順序に解説
- 6行目
変数res2が宣言されて、res2に”変更値”が代入(初期化)されます。 - 7行目
コンソールにrest2の値”変更値”が出力 - 8行目
nameFunc1(name1: &res2)が関数func nameFunc2(name2: String) を呼び出します。 - 8行目、1行目
8行目のrest2のアドレスが1行目のname2に渡されて同じアドレスになります。(参照渡し)
rest2の値”変更値”は渡されません。 - 2行目
関数内にある定数name2が宣言されて、再定義されています。併せてname2に”初期値”を代入
1行目のname2にはinoutキーワードが付いているので関数内にあるname2と同一になります。 - 3行目
コンソールに2行目のname2の値”初期値”が出力 - 9行目
rest2はname2と同じアドレスのためname2の値”初期値”が代入されています。そのためコンソールには”初期値”が出力
Swiftにおける&
記号は、関数に引数を渡す際にinout
パラメータとしてその引数のメモリアドレスを直接渡すことを意味します。
inout
キーワードが付いたパラメータは、関数の外部にある変数の値を関数内で変更できるようにするために使用されます。この機能により、関数は引数として受け取った変数の実際の値を直接更新することが可能になります。
&
の使用法inout
パラメータを持つ関数を呼び出す際、対象の変数の前に&
を置きます。これにより、Swiftはその変数のメモリアドレスを関数に渡すことができます。&
の意味&
は、変数の「参照」を関数に渡すことを意味します。これにより、関数内で行われる変数の変更は、関数の呼び出し元においても反映されます。
値渡しと参照渡しの違いを比較
項目 | 値渡し | 参照渡し |
---|---|---|
仕組み | 変数の値を渡す | 変数のメモリアドレスを渡す |
メリット | メモリ効率が良い | コードの簡潔化 |
デメリット | 関数内で変更しても元の変数には反映されない | メモリ管理が複雑 |
スッキリと理解できない場合の直感的な理解方法
プログラミングにおける参照渡しと値渡しの違いを理解するために、Windowsのファイル管理における「ファイルのショートカットを作る」行為と「ファイルのコピーを作る」行為との比較で理解してみましょう。
ただし、このアナロジーは、プログラミングの概念を視覚的に理解するのに役立ちますが、実際のメモリ管理や変数の扱いにおいては、プログラミング言語の具体的な挙動や安全性の観点から、より複雑な要素が関わってくることを理解しておくことが重要です。
値渡し(ファイルのコピー)
値渡しは、ある変数の内容(値)を別の変数にコピーするプロセスです。
これは、ファイルをコピーして新しい場所に配置する行為に似ています。
コピーされたファイルは元のファイルと全く同じ内容を持ちますが、それぞれが異なる場所(メモリアドレス)に存在します。このため、一方を変更しても、もう一方には影響しません。
参照渡し(ファイルのショートカット)
参照渡しは、変数の実際のメモリアドレス(参照)が渡されます。
これは、ファイルのショートカットを作る行為と類似しています。
ショートカットは元のファイルへのポインタ(リンク)のようなもので、ショートカットを通じて元のファイルが開かれます。
参照渡しの場合、関数やメソッド内で変数の値を変更すると、その変更は元の変数に反映されます。これは、ショートカットを介してファイルを編集すると、その変更が元のファイルにも適用されることに相当します。
FAQ
まとめ
関数に引数を渡す際、Swiftでは値渡しと参照渡しの2通りの方法があります。値渡しでは引数の値自体がコピーされて関数に渡され、参照渡しでは引数のメモリアドレスが渡されます。
値渡しの場合、コピーを渡すので関数内で引数を変更しても呼び出し元の変数には影響しません。
参照渡しの場合は影響が及び、呼び出し元の変数も変更されます。
参照渡しを行うには、関数のパラメータに「inout」キーワードを指定し、呼び出し時には変数の前に&を付けます。
これによりその変数への参照が渡されます。
関数内でパラメータを再定義すると、値渡しか参照渡しかに関わらず、呼び出し元の変数とは別のローカル変数を指すことになります。混乱を避けるため、再定義は避けて別名にすることをおすすめします。
値渡しと参照渡しの違いを理解する一助として、Windowsのファイル操作を例に考えることができます。
値渡しはファイルのコピーのように元とは独立した別物であり、参照渡しはショートカットのように元への参照を渡しているとイメージすることができます。