関数のようにはたらく新しい型を定義しつつ、ラムダ式を使ってオブジェクト生成したい場合に。
背景
Javaでは抽象メソッドが一つだけあるインターフェース(=関数型インターフェース)のオブジェクトはラムダ式で生成できます。
@FunctionalInterface
interface Composable {
int apply(int v);
default Composable compose(Composable other) {
return v -> { return this.apply(other.apply(v)); };
}
}
class Main {
public static void main(String[] args) {
Composable f = v -> { return v + 2; };
Composable g = v -> { return v * 2; };
System.out.println(f.compose(g).apply(2));
}
}
Kotlinでもラムダ式や無名関数が用意されていて、これを使って関数型のオブジェクトを生成できます。しかし、これはあくまで関数オブジェクトを生成するためのもので、関数のような何か、例えば関数型を継承したインターフェースのオブジェクトを生成することは出来ません。
従って次のコードはコンパイルエラーとなります。
interface Composable {
fun apply(v: Int): Int
fun compose(other: Composable): Composable = { this.apply(other.apply(it)) }
}
fun main(args: Array<String>) {
val f: Composable = { it + 2 }
val g: Composable = { it * 2 }
println(f.compose(g).apply(2))
}
代わりに
object : Composable {
override fun apply(v: Int): Int { ... }
}
といちいち書かなければならず煩わしいです。
方法
関数を受け取り、インターフェースを返す関数を定義します。実際の処理は受け取った関数に委譲します。
interface Composable {
fun apply(v: Int): Int
fun compose(other: Composable): Composable = composable { this.apply(other.apply(it)) }
}
fun composable(f: (Int) -> Int) = object : Composable {
override fun apply(v: Int): Int = f(v)
}
fun main(args: Array<String>) {
val f = composable { it + 2 }
val g = composable { it * 2 }
println(f.compose(g).apply(2))
}