KotlinLearning: 04-2 関数型

18/03/2021

関数型

既に04-1で確認しましたが、匿名関数は関数型の変数として参照を保持することができます。
変数に匿名関数を保持することによって、他の変数と同様、匿名関数をコード間で渡すことができます。

val greetingFunction: () -> String = {
  val name = "NO NAME"
  "Hello, $name"
}
println(greetingFunction())

() -> Stringは引数なしでString型を返す関数型の定義で、変数greetingFunctionはこの() -> String型の関数を保持することを表しています。
変数名greetingFunctionの後ろに()をつけることにより、任意のタイミングで変数に格納された関数を実行することができます。

暗黙的なreturn

例えば上記のgreetingFunction変数に格納した匿名関数はreturnキーワードはありません。
名前付き関数と異なり匿名関数ではreturnキーワードは不要で、関数本体の最後の行を戻り値として返します。

関数パラメーター

名前付き関数と同様、匿名関数は引数を取らないか任意のタイプの1つ以上の引数を取ることができます。
引数が必要な場合、引数の型は匿名関数の型定義に配置され、引数名は匿名関数の定義に配置されます。

val 関数型の変数名: (引数の型) -> 戻り値の型 = {引数名 ->
...
val greetingFunction: (String) -> String = {playerName ->
  val currentYear = 2021
  "Welcome to KotlinGame, $playerName! (copyright $currentYear)"
}
println(greetingFunction("IDEA"))
//Welcome to KotlinGame, IDEA! (copyright 2021)

上記は匿名関数がString型の引数を取ることを表し、匿名関数内でplayerNameという変数名でString型の引数を扱うことを示しています。

val greetingFunction: (String) -> String = {playerName ->
...

itキーワード

引数が一つだけの匿名関数を定義する場合、匿名関数の定義で引数名を明示せず、itキーワードで変数の値を取得することができます。

val greetingFunction: (String) -> String = {
  val currentYear = 2021
  "Welcome to KotlinGame, $it! (copyright $currentYear)"
}
println(greetingFunction("IDEA"))

itキーワードは引数が1つである場合のみ使用できます。
匿名関数が複数の引数を受け取る場合は各引数に名前を付ける必要があります。

val greetingFunction: (String, Int) -> String = {playerName, currentYear ->
  "Welcome to KotlinGame, $playerName! (copyright $currentYear)"
}
println(greetingFunction("IDEA", 2021))

型推論

Kotlinでは変数を定義する際、型が明らかであれば型推論をすることができました。

//val greetingMessage: String = "Welcome to KotlinGame!"
val greetingMessage = "Welcome to KotlinGame!"

関数型でもKotlinの型推論を使用できます。
つまり関数型の変数を定義する際、匿名関数の型を明示する必要はありません。

val greetingFunction: () -> String = {
  val currentYear = 2021
  "Welcome to KotlinGame, IDEA! (copyright $currentYear)"
}

上記は以下のように型推論することができます。

val greetingFunction = {
  val currentYear = 2021
  "Welcome to KotlinGame, IDEA! (copyright $currentYear)"
}

型推論は引数付きの匿名関数でも使用できますが、その場合表記法が異なります。
コンパイラが変数型をより正確に推論できるよう、匿名関数内で引数名と引数型を持つ必要があります。

val greetingFunction = {playerName:String, currentYear:Int ->
  "Welcome to KotlinGame, $playerName! (copyright $currentYear)"
}
println(greetingFunction("IDEA", 2021))

上記を型推論しない場合は以下の様に表記します。

val greetingFunction: (String, Int) -> String = {playerName, currentYear ->
  "Welcome to KotlinGame, $playerName! (copyright $currentYear)"
}
println(greetingFunction("IDEA", 2021))

どちらが読みやすいかは好みに寄るでしょう。
チーム内で統一しておく方が可読性がよいと思います。

Advertisements

Kotlin

Posted by codive