匿名関数
ラムダ式では返り値の型を明示的に指定することができません。
明示的に指定できなくても、自動的に推測してくれるため、大抵の場合は問題ありません。
しかし、何らかの事情で返り値の型を明示的に指定したい場合、「匿名関数」を利用することができます。
匿名関数とは、その名前の通り関数名(関数の識別子)を持たない関数のことです。
fun(引数リスト): 返り値の型 = 式
fun(引数リスト): 返り値の型 {
式
}
上記のように、関数名がないこと以外は普通の関数と同じです。
それでは、サンプルを見てみましょう。
fun main(args: Array) {
val fruits = listOf("apple", "banana", "orange", "peach")
// 関数名の前に::をつけることで関数を参照を取得できる
val subList = filter(
fruits,
fun(str: String): Boolean = str.contains('p', true) )
println(subList)
}
fun filter(source: List, condition: (String) -> Boolean): List {
val ret = mutableListOf()
for (i in source) {
if (condition(i)) {
ret.add(i)
}
}
return ret;
}
[apple, peach]
関数リテラルと関数型
Kotlinにおいて、ラムダ式と匿名関数は関数リテラルとして扱われます。
数値リテラルや文字列リテラルなどと同じように、変数に代入することができます。
fun main(args: Array) {
val fruits = listOf("apple", "banana", "orange", "peach")
// 変数に代入できる
val anonymous = fun(str: String): Boolean = str.contains('p', true)
val lamda = { str: String -> str.contains('p', true) }
val subList = filter(fruits, anonymous)
println(subList)
val subListLamda = filter(fruits, lamda)
println(subListLamda)
}
fun filter(source: List, condition: (String) -> Boolean): List {
val ret = mutableListOf()
for (i in source) {
if (condition(i)) {
ret.add(i)
}
}
return ret;
}
[apple, peach]
[apple, peach]
また、上記のサンプルのfilter関数のcondition引数のように、
引数の型と返り値の型から関数型を指定することができます。
fun main(args: Array) {
val fruits = listOf("apple", "banana", "orange", "peach")
// 型を指定して変数を宣言
val anonymous: (String) -> Boolean
val lamda: (String) -> Boolean
anonymous = fun(str: String): Boolean = str.contains('p', true)
// 引数の型が一つしかないことがわかっているので、itを利用できる
lamda = { it.contains('p', true) }
val subList = filter(fruits, anonymous)
println(subList)
val subListLamda = filter(fruits, lamda)
println(subListLamda)
}
fun filter(source: List, condition: (String) -> Boolean): List {
val ret = mutableListOf()
for (i in source) {
if (condition(i)) {
ret.add(i)
}
}
return ret;
}
[apple, peach]
[apple, peach]
クロージャ
ラムダ式や匿名関数の変数は、クロージャとして機能しています。
つまり、ラムダ式や匿名関数自身が定義されたスコープにアクセスできます。
fun main(args: Array) {
val fruits = listOf("apple", "banana", "orange", "peach")
var str = ""
fruits.filter {
it.contains('p', true)
}.forEach {
// このラムダ式が定義されてるスコープ、つまり「fun main」のスコープにアクセスできる。
// そのため、fun mainスコープの変数であるstrを操作できる。
str += it;
str += "\n"
}
print(str);
}
apple
peach