web-dev-qa-db-ja.com

インターフェイスの代わりにラムダを渡す

インターフェースを作成しました:

interface ProgressListener {
    fun transferred(bytesUploaded: Long)
}

ただし、ラムダではなく匿名クラスとしてのみ使用できます

dataManager.createAndSubmitSendIt(title, message,
object : ProgressListener {
    override fun transferred(bytesUploaded: Long) {
        System.out.println(bytesUploaded.toString())
    }
})

私はそれをラムダに置き換える可能性があると思う:

dataManager.createAndSubmitSendIt(title, message, {System.out.println(it.toString())})

しかし、エラーが発生しています:型の不一致。必須-ProgressListener、見つかった-()-> Unit?

何が間違っていますか?

52

@ zsmb13が言ったように、SAM変換はJavaインターフェイスでのみサポートされています。

ただし、機能する拡張機能を作成することもできます。

// Assuming the type of dataManager is DataManager.
fun DataManager.createAndSubmitSendIt(title: String, 
                                      message: String, 
                                      progressListener: (Long) -> Unit) {
    createAndSubmitSendIt(title, message,
        object : ProgressListener {
            override fun transferred(bytesUploaded: Long) {
                progressListener(bytesUploaded)
            }
        })
}
33
marstran

Kotlinは、JavaインターフェイスのSAM変換のみをサポートします。

...この機能はJava interopに対してのみ機能します。Kotlinには適切な関数タイプがあるため、Kotlinインターフェイスの実装への関数の自動変換は不要であり、サポートされていません。

- 公式ドキュメント

パラメーターでラムダを使用する場合は、関数がインターフェイスではなく関数パラメーターを取るようにします。 (少なくとも今のところ。KotlinインターフェースのSAM変換のサポートは継続的な議論であり、Kotlin 1.1ライブストリームで将来可能な機能の1つでした。)

27
zsmb13

少し遅れて:インターフェイスを作成する代わりに、次のように、データマネージャーのインターフェイスの代わりに関数を直接使用することで、コンパイルで作成できるようにします。

fun createAndSubmitSendIt(title: String, message: String, transferred: (Long) -> Unit) {
    val answer = TODO("whatever you need to do")
    transferred(answer)
}

そして、あなたはそれをあなたが望むように使うだけです!私の記憶が正しければ、kotlin/jvmコンパイラーが行うことは、インターフェースを作成することと同じです。

それが役に立てば幸い!

8
Louis Tsai

別の解決策は、typealiasを宣言し、どこかに挿入して呼び出すことです。ここに例:

internal typealias WhateverListener = (String) -> Unit

そして、そのタイプエイリアスをクラスに注入します:

class Gallery constructor(private val whateverListener: WhateverListener) {

    ...

    galleryItemClickListener.invoke("hello")

    ...
}

ラムダがあります:

val gallery = Gallery { appNavigator.openVideoPlayer(it) }

同僚のジョエル・ペドラザに謝辞.

3
cesards