回答編集履歴

1

3つ目の質問に対する例題を追記

2020/03/21 16:08

投稿

TsukubaDepot
TsukubaDepot

スコア5086

test CHANGED
@@ -224,6 +224,158 @@
224
224
 
225
225
 
226
226
 
227
+ 私が少し勘違いと混乱していたようです。
228
+
229
+ `&`を取ってコンパイルするとエラーになるはずですが、質問者さんの環境ではいかがでしょうか。
230
+
231
+
232
+
233
+ ![&の不足](72c52d5fa4b23b8520eb2e08bc4601ec.png)
234
+
235
+
236
+
227
- これは、質問者さんのご指摘は尤もかますが、まだ自分でも納得のゆくよな説明方法見つかりません
237
+ したがって、具体的な影響としては、まず「コンパイルに通らない」という影響りま
238
+
239
+
240
+
228
-
241
+ 理由ですが、英語による Swift のマニュアルのうち、[In-Out Parametersの項](https://docs.swift.org/swift-book/LanguageGuide/Functions.html#ID173)をみるとこのように記述してあります。
242
+
243
+
244
+
245
+ > 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.
246
+
247
+
248
+
249
+ また、参考文献[1]では「ここで使っている`&`という記号は通常の演算子ではなく、`inout`引数に対応する実引数で表す記法です」とあり(p.44)、参考文献[2]では「インアウト引数を持つ関数を呼び出すには、インアウト引数の先頭に`&`を加えます」とあります(p.110)。
250
+
251
+
252
+
253
+ C言語をやっていたらアドレス演算子としての印象が強く、`&`という記号そのものに何らかの操作があるように感じます(し、私の場合はついその印象で考えてしまいました)。
254
+
255
+
256
+
257
+ しかし英文マニュアルの説明などを見る限り、Swiftでは`&`を付与することによって特別な操作があるわけではなく、`&`をつけることによって、引数として与えられた変数が書き換えられるということを明示的に示していると考えられます。
258
+
259
+
260
+
261
+ では、そもそも何故値渡しではなく`&`をつけて参照渡しするのかというと、処理先の関数の中で実引数として渡したプロパティが参照しているインスタンスそのものを書き換えているからです。
262
+
263
+
264
+
229
- もうちょっと考えてみますが、とりあえず上記2点だけ先に回答しおき
265
+ あんり良い例題ではないですが、こんなサンプルを作っした
266
+
267
+
268
+
269
+ ```swift
270
+
271
+ import UIKit
272
+
273
+
274
+
275
+ class ClassA {
276
+
277
+ var msg: String
278
+
279
+ init(msg: String) {
280
+
281
+ self.msg = msg
282
+
283
+ }
284
+
285
+ deinit {
286
+
287
+ print("deinit - msg: (msg)")
288
+
289
+ }
290
+
291
+ }
292
+
293
+
294
+
295
+ func newClass(cl: ClassA){
296
+
297
+ // Swift は仮引数の値は書き換えられないので、同名の別の変数に置き換える
298
+
299
+ // 参考文献[1]p.46
300
+
301
+ var cl = cl
302
+
303
+ cl = ClassA(msg: "newClass内で作ったインスタンス")
304
+
305
+ }
306
+
307
+
308
+
309
+ func newClassWithInout(cl: inout ClassA){
310
+
311
+ cl = ClassA(msg: "newClassWithInout内で作ったインスタンス")
312
+
313
+ }
314
+
315
+
316
+
317
+ do{
318
+
319
+ print("inout 無しで呼び出し")
320
+
321
+ var clA = ClassA(msg: "最初のインスタンス")
322
+
323
+ print("newClass呼び出し前 - msg: (clA.msg)")
324
+
325
+ newClass(cl: clA)
326
+
327
+ print("newClass呼び出し後 - msg: (clA.msg)")
328
+
329
+ }
330
+
331
+
332
+
333
+ print("")
334
+
335
+
336
+
337
+ do{
338
+
339
+ print("inout 付きで呼び出し")
340
+
341
+ var clA = ClassA(msg: "最初のインスタンス")
342
+
343
+ print("newClass呼び出し前 - msg: (clA.msg)")
344
+
345
+ newClassWithInout(cl: &clA)
346
+
347
+ print("newClass呼び出し後 - msg: (clA.msg)")
348
+
349
+ }
350
+
351
+ ```
352
+
353
+ 実行すると、こんな感じになると思います。
354
+
355
+ ```
356
+
357
+ inout 無しで呼び出し
358
+
359
+ newClass呼び出し前 - msg: 最初のインスタンス
360
+
361
+ deinit - msg: newClass内で作ったインスタンス
362
+
363
+ newClass呼び出し後 - msg: 最初のインスタンス
364
+
365
+ deinit - msg: 最初のインスタンス
366
+
367
+
368
+
369
+ inout 付きで呼び出し
370
+
371
+ newClass呼び出し前 - msg: 最初のインスタンス
372
+
373
+ deinit - msg: 最初のインスタンス
374
+
375
+ newClass呼び出し後 - msg: newClassWithInout内で作ったインスタンス
376
+
377
+ deinit - msg: newClassWithInout内で作ったインスタンス
378
+
379
+ ```
380
+
381
+ 注意深く読まないと分かりにくいとおもいますし、もっと細かく`print()`をいれて動作を確認する必要はあると思いますが、`inout`あり無しの処理において、最初に作ったインスタンスと、関数内で新たに作ったインスタンスのライフサイクルの違いはわかるかと思います。