質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.44%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

2回答

377閲覧

クロージャやコールバックに関してコードが理解できない部分がある

pecchan

総合スコア591

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2024/03/05 03:07

困っていること

swift勉強中の者です。
現在、クロージャ、コールバック辺りについて学んでいるところです。
ネット上のサンプルを動かしてるのですが、コードが正しく読み解けない部分があり苦戦してます。

先輩方教えて下さい。
宜しくお願いします。

分からないこと

コールバック関数と呼び出し元とで「引数」と「戻り値」の型が合っていない、ようにしか読み解けない。。。
なぜこのような記述になるのか分からない。

・引数について

クロージャの部分は以下のようにIntを引数に取るように宣言されてます。

swift

1func incrementAge(completion: (Int) -> Void)

なので呼び出し元では、このようにIntを渡すのでないか?と思うのですが、これだと
「error: consecutive statements on a line must be separated by ';'
me.incrementAge(completion:{50 in」というエラーになってしまいます。

swift

1me.incrementAge(completion:{50 in

このように呼ぶのが正しいようです。(急に出てきたretって何?retでもhogeでも実行できた)

swift

1me.incrementAge(completion:{ret in

・戻り値について

コールバック関数側はVoidだが

swift

1func incrementAge(completion: (Int) -> Void)

呼び出し元ではこれでIntを受け取れている。

swift

1print(ret)

該当のソースコード

swift

1 2class Person { 3 var age: Int = 30 4 func incrementAge(completion: (Int) -> Void) { 5 age = age + 5 6 completion(age) 7 } 8} 9 10let me = Person() 11me.incrementAge(completion:{ret in 12 print(ret) 13})

試したこと

・一行ずつprint()して処理の順番だけは理解できました

・引数をIntに変えてみた

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

Swiftにおいてはクロージャ式と関数は同じものとみなして問題ありません。

incrementAge(completion:)メソッドの引数の型である(Int) -> Voidは関数で表すと

swift

1func f(_ i: Int) -> Void { 2 print(i) 3}

のように引数にIntをとり何も返さない関数のことです。(何もないをVoidで表します)
関数定義では戻り値の型がVoidの場合は省略が可能です。

swift

1func f(_ i: Int) { 2 print(i) 3}

この関数はこのままincrementAge(completion:)メソッドに渡すことが可能です。

swift

1let me = Person() 2me.incrementAge(completion: f)

また関数fと同じものをクロージャ式で書くことが可能です。

swift

1let g: (Int) -> Void = { (i: Int) -> Void in 2 print(i) 3}

inの前の部分に仮引数(この場合はi)を含んだ形でクロージャ式の型を書きます。
クロージャ式ではいろいろ省略が可能ですのですべて省略すると

swift

1let g: (Int) -> Void = { i in 2 print(i) 3}

となります。

このクロージャ式gincrementAge(completion:)メソッドに渡すと

swift

1let me = Person() 2me.incrementAge(completion: g)

となります。
このときクロージャ式を変数gに入れずにそのままincrementAge(completion:)メソッドに渡すことも可能です。
gの部分にクロージャ式をそのまま入れればいいだけです。

swift

1let me = Person() 2me.incrementAge(completion: { i in 3 print(i) 4})

これがソースコードの最後に書かれているものになります。

投稿2024/03/05 09:30

MasakiHori

総合スコア3391

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pecchan

2024/03/05 09:55

丁寧に順に解説してくださり有難う御座います。 おかげで理解できました。
guest

0

クロージャの部分は以下のようにIntを引数に取るように宣言されてます。

そこから間違っています。incrementAgeの引数は「引数がInt型一つで結果がVoidの関数」です。
文法に従って読みましょうとしか言いようがないです。

コールバックという概念は理解されているようなので、「関数の引数に関数を渡す」ことの理解は大丈夫ですよね?
おそらく、冒頭の間違いが分かれば、あとはおわかりになるかと思いますので、以降の説明は割愛します。

と書いた物の、質問を読み返すと、誤読してたような気がしますので、追記しておきます。

クロージャの部分は以下のようにIntを引数に取るように宣言されてます。

とお書きなのは、completionという仮引数の型の部分であると思いますが、
コードにあるとおりcompletionという名前の仮引数は「引数がInt型一つで結果がVoidの関数」です。
対応する実引数は、クロージャーでもいいし、名前を持った関数の名前でも良いはずです。
なので、「クロージャの部分は」という表現は正しくなく、「コールバック関数の部分は」でしょうか。

実引数は、下記のクロージャーで、これは「引数がInt型一つで結果がVoidの関数」なので、型は合っています。

Swift

1{ret in 2 print(ret) 3}

retは仮引数名なので何でもいい。型は推論でIntですかね。

投稿2024/03/05 06:06

編集2024/03/05 08:49
otn

総合スコア84882

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

pecchan

2024/03/05 09:54

わざわざ追記までしてくださり有難う御座います。 型推論の解説でしっくり腑に落ちました。 やっと理解できました。
otn

2024/03/05 10:04

そうか。 「50 in 」と書いてみたと言うことは、そもそも「クロージャーの構文」「クロージャーとは何か」から理解できてなかったということで、そこから説明が必要だったんですね。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.44%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問