Posted at

KotlinでSAM(Single Abstract Method)インターフェースを作ったら省略記法が使えなかった話

More than 1 year has passed since last update.


問題

JavaでInterface定義し、抽象メソッドが一つだけのもの(Single Abstract Method: SAM)をKotlinで呼び出すときは下記みたいな感じでいける

view.setOnClickListener { view ->

// something
}

一方、下記のようにKotlinでSAMのInterfaceを作っても同じように呼び出せない


  • 呼ばれる側

interface HogeListener {

fun fuga(s: String)
}

setHogeListener(listener: HogeListener) {
this.listener = listener
}


  • 呼ぶ側

hogehoge.setHogeListener { s ->

}
// ERROR:
// Type Mismatch.
// Required: A.HogeListener
// Found: (???) -> Unit
// Cannot infer a type for this parameter. Please specify it explicitly.


原因

https://kotlinlang.org/docs/reference/java-interop.html#sam-conversions

Also note that this feature works only for Java interop; since Kotlin has proper function types, automatic conversion of functions into implementations of Kotlin interfaces is unnecessary and therefore unsupported.

JavaのSAMはよしなに変換してくれるけど、Kotlinは必要ないから変換しないとのこと。


対応

とりあえずJavaの時と使い勝手を変えたくなかったので下記のように実装。

class Hoge(private var listener: (String) -> Unit) {

fun fuga(string: String) {
listener(string)
}
}

setHogeListener(listener: (String)->Unit) {
listener = Hoge(listener)
}

実際にはKotlin化と同時に不要なインターフェースを無くしていくのがベストなんだろなぁと思いつつ、一時対応としてメモ。