回答編集履歴
1
3つ目の質問に対する例題を追記
answer
CHANGED
@@ -111,5 +111,81 @@
|
|
111
111
|
> "「soundPlayer」処理後にシンバルの情報を呼び出し元に戻して利用したいので、参照渡しにしている"
|
112
112
|
> と記載されています。実際には&なしでコーディングしても結果、動作させても影響がない様に思えるのですが、具体的にどの様な影響があり、なぜ参照渡しにすべきなのかアドバイスをを頂戴できると大変嬉しいで す。
|
113
113
|
|
114
|
+
私が少し勘違いと混乱していたようです。
|
115
|
+
`&`を取ってコンパイルするとエラーになるはずですが、質問者さんの環境ではいかがでしょうか。
|
116
|
+
|
117
|
+

|
118
|
+
|
114
|
-
|
119
|
+
したがって、具体的な影響としては、まず「コンパイルに通らない」という影響があります。
|
120
|
+
|
121
|
+
理由ですが、英語による Swift のマニュアルのうち、[In-Out Parametersの項](https://docs.swift.org/swift-book/LanguageGuide/Functions.html#ID173)をみるとこのように記述してあります。
|
122
|
+
|
123
|
+
> You place an ampersand (&) directly before a variable’s name when you pass it as an argument to an in-out parameter, to indicate that it can be modified by the function.
|
124
|
+
|
125
|
+
また、参考文献[1]では「ここで使っている`&`という記号は通常の演算子ではなく、`inout`引数に対応する実引数で表す記法です」とあり(p.44)、参考文献[2]では「インアウト引数を持つ関数を呼び出すには、インアウト引数の先頭に`&`を加えます」とあります(p.110)。
|
126
|
+
|
127
|
+
C言語をやっていたらアドレス演算子としての印象が強く、`&`という記号そのものに何らかの操作があるように感じます(し、私の場合はついその印象で考えてしまいました)。
|
128
|
+
|
129
|
+
しかし英文マニュアルの説明などを見る限り、Swiftでは`&`を付与することによって特別な操作があるわけではなく、`&`をつけることによって、引数として与えられた変数が書き換えられるということを明示的に示していると考えられます。
|
130
|
+
|
131
|
+
では、そもそも何故値渡しではなく`&`をつけて参照渡しするのかというと、処理先の関数の中で実引数として渡したプロパティが参照しているインスタンスそのものを書き換えているからです。
|
132
|
+
|
115
|
-
|
133
|
+
あんまり良い例題ではないですが、こんなサンプルを作ってみました。
|
134
|
+
|
135
|
+
```swift
|
136
|
+
import UIKit
|
137
|
+
|
138
|
+
class ClassA {
|
139
|
+
var msg: String
|
140
|
+
init(msg: String) {
|
141
|
+
self.msg = msg
|
142
|
+
}
|
143
|
+
deinit {
|
144
|
+
print("deinit - msg: (msg)")
|
145
|
+
}
|
146
|
+
}
|
147
|
+
|
148
|
+
func newClass(cl: ClassA){
|
149
|
+
// Swift は仮引数の値は書き換えられないので、同名の別の変数に置き換える
|
150
|
+
// 参考文献[1]p.46
|
151
|
+
var cl = cl
|
152
|
+
cl = ClassA(msg: "newClass内で作ったインスタンス")
|
153
|
+
}
|
154
|
+
|
155
|
+
func newClassWithInout(cl: inout ClassA){
|
156
|
+
cl = ClassA(msg: "newClassWithInout内で作ったインスタンス")
|
157
|
+
}
|
158
|
+
|
159
|
+
do{
|
160
|
+
print("inout 無しで呼び出し")
|
161
|
+
var clA = ClassA(msg: "最初のインスタンス")
|
162
|
+
print("newClass呼び出し前 - msg: (clA.msg)")
|
163
|
+
newClass(cl: clA)
|
164
|
+
print("newClass呼び出し後 - msg: (clA.msg)")
|
165
|
+
}
|
166
|
+
|
167
|
+
print("")
|
168
|
+
|
169
|
+
do{
|
170
|
+
print("inout 付きで呼び出し")
|
171
|
+
var clA = ClassA(msg: "最初のインスタンス")
|
172
|
+
print("newClass呼び出し前 - msg: (clA.msg)")
|
173
|
+
newClassWithInout(cl: &clA)
|
174
|
+
print("newClass呼び出し後 - msg: (clA.msg)")
|
175
|
+
}
|
176
|
+
```
|
177
|
+
実行すると、こんな感じになると思います。
|
178
|
+
```
|
179
|
+
inout 無しで呼び出し
|
180
|
+
newClass呼び出し前 - msg: 最初のインスタンス
|
181
|
+
deinit - msg: newClass内で作ったインスタンス
|
182
|
+
newClass呼び出し後 - msg: 最初のインスタンス
|
183
|
+
deinit - msg: 最初のインスタンス
|
184
|
+
|
185
|
+
inout 付きで呼び出し
|
186
|
+
newClass呼び出し前 - msg: 最初のインスタンス
|
187
|
+
deinit - msg: 最初のインスタンス
|
188
|
+
newClass呼び出し後 - msg: newClassWithInout内で作ったインスタンス
|
189
|
+
deinit - msg: newClassWithInout内で作ったインスタンス
|
190
|
+
```
|
191
|
+
注意深く読まないと分かりにくいとおもいますし、もっと細かく`print()`をいれて動作を確認する必要はあると思いますが、`inout`あり無しの処理において、最初に作ったインスタンスと、関数内で新たに作ったインスタンスのライフサイクルの違いはわかるかと思います。
|