LoginSignup
2
2

More than 5 years have passed since last update.

KotlinでJavaの関数型インターフェースを模倣する

Last updated at Posted at 2017-07-11

関数のようにはたらく新しい型を定義しつつ、ラムダ式を使ってオブジェクト生成したい場合に。

背景

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))
}
2
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2