swift

Swift超入門_関数とクロージャ的な何か

投稿日:

仮引数と省略

swift初心者(おっさん)が一見して理解できなかったのが関数の仮引数の前にあるアンダースコア(_)。
swift全般的にアンダースコアが言語仕様に含まれているので、いろいろ調べてみた。

単に、関数を呼び出す際にキーワード引数の名称を省略するための記法だった。
仮引数の前にアンダースコア(_)を置くと、呼び出し時にキーワード無しで引数を呼べる。

Swiftは、仮引数と実引数を違う名前で定義できる。
以下、param2というキーワードを使ってhoge3を呼び出しているが、
hoge3の中では仮引数param2をparam3として使っている。
一般に、param3をparam1と関係がある名称にすることで冗長にさせない工夫。

デフォルト引数は一般的。

関数の定義名に特徴がある。hoge4の定義名は以下のようになる。
ObjectiveCっぽい。

インアウト引数

いわゆる参照渡し。
仮引数にinout予約語をつけておくと、仮引数の操作が実引数に反映される。
呼び出す際に、引数に&をつける。

可変長引数

可変長引数はスリードット(...)を指定し、配列(Array)で受ける。

クロージャ

さて、Swiftのクロージャ。まぁ何回か使ったら慣れるだろうぐらい分かりづらくはない。
前置詞のinがクロージャブロックの開始になってるのは意図があるんだろうか。

クロージャの引数の型と戻り値の型は型推論が効く。

クロージャの簡易引数名

クロージャの引数名すら書きなくない場合もある。
前置詞inではなく、一般的なブラケットでクロージャブロックを書く。
クロージャブロックからは、n番目のパラメタを$nとして受け取る。

クロージャによる変数束縛

クロージャの実行時にクロージャ呼び出し元の環境を利用できる。
文脈によって呼び出し元の環境は異なるので、実行時に環境のスナップショットを取るイメージ。
Swiftでは"キャプチャ"という名前で呼んでいるらしい。
例えば以下。クロージャ add:(Int,Int)-> Int 内で呼び出し元の変数pを使っている。
クロージャ呼び出し時に呼び出し元の環境に依存してpの値が決まる。
なお、pが初期化済みでない状態でクロージャを定義するとエラーになる。
クロージャの実行前にキャプチャする変数は初期化されている必要があるらしい。

クロージャ内でキャプチャした変数を書き換えた場合、キャプチャ元になった変数自体が変わる。

autoclosure属性

引数の遅延評価を行う指令。
論理和を計算する関数を定義しようとしたとき、Bool型の引数を2つ取ってBool型の戻り値を返す
関数を定義するとする。
論理和なので、どちらかが真であれば一方の引数を見なくても結果がわかるのだが、
下記のようにすると、どちらかが真であっても、もう一方の引数を評価して返すことになる。

引数をクロージャとし、クロージャ内で引数の評価の必要性を判断するようにして、
クロージャを遅延評価(関数内での評価)することで不要な引数の評価を回避するというアイデア。

or2の第2引数が複雑になってしまうところを、文法解決で簡単に書けるようにするのが@autoclosure。
引数をクロージャで包む書き方を省略できる。
下記のように書ける。

trailing closure

引数の最後がクロージャである場合、その引数の前で引数のブラケットを閉じて、
その後にクロージャを書くことができる。
例えば以下のような感じ。
1つ目は真面目に引数の最後にクロージャを与えている。
2つ目は関数呼び出しの後にクロージャを書いている。

関数をクロージャとして扱う

関数をクロージャとして扱うことができる。関数double(_:)は(Int)->Int型。
それをfunctionという定数の初期値に設定している。
functionには型アノテーションがないけれども、
double(_:)が(Int)->Intなので型推論されて(Int)->Intになる。

関数の引数としてクロージャを与えるシーンで、
クロージャを関数として用意しておくことで、それぞれの呼び出しでクロージャを定義する必要がなくなる。
下記について、上はmapの引数としてそれぞれクロージャを定義して呼び出している。
同じ処理をするのに2回定義しないといけない。
下は、関数を定義し、mapの引数として関数をクロージャとして与えている。
関数(クロージャ)の定義は1回で良い。

-swift
-

Copyright© ikuty.com , 2018 AllRights Reserved Powered by AFFINGER4.