Swift

Swift:クロージャを利用したコールバック処理


Swiftに限らずプログラミングを勉強していると出てくるコールバックですが、
言語によって書き方が若干異なります。

覚えておくと便利なので、しっかりメモしていきます!

 

そもそもコールバックって??

 

コールバックとは、call backです。

つまり「あとで呼ぶ」ということになります。

ある関数の中で別の関数を呼ぶイメージです。

結構シンプルです。

 

こういった関数の中で関数を呼ぶ処理はよく書かれると思います。

これはコールバックではありませんが、非常に近い例です。

 

コールバックでかく

上の例をコールバックに直してみます。

 

このようになります。

解説していきます!

function: (Void) -> Void

難しいのはこの辺ですよね。

functionは引数名です。正直なんでもOKです!

(Void) -> Voidは引数の型です。(型) ->型 で関数を表現することができます。
Voidは「空っぽ」の意味です。

 

つまり

「Voidを引数にとりVoidを戻り値にとる関数」== 「引数を取らない戻り値のない関数」

ということになります。

 

でも、関数bbb内にVoidがかかれてない??

そうなんです、実は上記の関数bbbは省略された書き方なんです。

Voidの意味は空っぽなので、省略できるのも納得ですよね。

関数bbbを省略せずに書くとこのようになります。

 

これによって「Voidを引数にとりVoidを戻り値にとる関数」である関数bbbを引数にとることができるのです。

 

じゃあfunction: (Void) -> Voidももっと短くかけるんじゃないか?

このような疑問は出てきますが、コールバック(関数の引数に関数をとる)の場合はVoidを省略することはできないのです。

 

Trailing Closure

Trailing Closureという記述方法があります。

直訳では「末尾にクロージャ」という意味になります。

これだけでは謎ですね。

百聞は一見に如かずです!とりあえずみてみましょう。

 

今までとは全く違うクールな書き方です。
aaa()の後ろに { } が来て、その中に処理を記述していきます。

今回の例が悪すぎて、

Trailing Closureにするメリットは全くないですがよく見る書き方なのでぜひマスターしたいところです。

特徴としては引数名のfunctionを書かなくても良いところですね。
別の例をあげます。

上の例よりはまともですが、少し難しいかもです。

引数”たけし”が入ったnameはcallbackの引数になり、Trailing Closureの『i』に送られます。

そしてreturnによってi( == name == “たけし”) に “はとても” が足されたものが返され、
最終的には “楽しい!!!” と合わさってprintされるという流れです。

Trailing Closureの魅力の一つは関数の後ろにある( )内から切り離して記述できるところです。
かっこよく・適切に使っていきましょう!!

 

コールバックではないけど関数を引数に取る関数

コールバックではないけど関数を引数に取る関数があります。

謎ですね。

こちらです。

関数cccがそれに当たりますね。

function: () の()によって関数を取ることを表現しています。

しかし、cccの中にfunctionの記述はありません。
にも関わらず、cccの引数にdddを格納するとしっかりと実行されます。

不思議ですよね。。。

これについては僕も全く理解できていないので、ご存知の方は教えていただけると嬉しいです。

2018年3月3日編集
こちらについてコメントで教えて頂いたので追記します!ありがとうございます!!
上記で「function: () の()によって関数を取ることを表現しています。」と書いていますが、
この考え方は間違っているようです!
()は関数を取ることを表現しているわけではなく、()の型エイリアスとしてVoidが定義されているから、cccはVoid型の値を引数に取るというような意味になる。』とのことでした。

わかりやすく省略の無いように書くとこのようになります。

 


コメント

  1. makki より:

    > コールバックではないけど関数を引数に取る関数
    こちらについてですが、cccに値を渡す際にdddを先に呼び、dddの戻り値をcccに渡しているからdddが実行されているので、関数を引数にとっている訳ではなく、関数の戻り値を引数にとっている状態です。
    また、()は関数を取ることを表現しているわけではありません。()の型エイリアスとしてVoidが定義されていますので、cccはVoid型の値を引数に取るというような意味になります。
    わかりやすくするために全てに型注釈を加えると以下のようになります。

    `swift
    func ccc(function: Void) -> Void {
    print(“cccです”)
    }

    func ddd(Void) -> Void {
    print(“dddです”)
    }

    ccc(function: ddd())
    // dddです
    // cccです

    // つまり、9行目でやっていることは以下と同義なので、関数が渡されている訳ではない
    let x: Void = ddd()
    ccc(function: x)

    1. ささお より:

      とても丁寧な解説ありがとうございます、勉強になりました!

      色々と勘違いしていました・・・
      頂いたコメントを参考に編集させていただきます!

      1. makki より:

        こちらこそお役に立てて幸いです。よいプログラミングライフを!

コメントを残す

*