Работает ли ключевое слово Kotlin `by для обнуляемого делегата? - PullRequest
0 голосов
/ 26 марта 2019

Меня очень порадовали возможности компилятора Kotlin и, в частности, by - это экономит время на генерацию геелатирующего кода:

https://kotlinlang.org/docs/reference/delegation.html

Но я хочу, чтобы делегат был обнуляемым и делегировал код, чтобы сначала проверить, является ли он нулевым, и вернуть, если он:

interface Base {
    val message: String
    fun print()
}

class BaseImpl(val x: Int?) : Base {
    override val message = "BaseImpl: x = $x"
    override fun print() { println(message) }
}

class Derived(b: Base?) : Base by b {
    // This property is not accessed from b's implementation of `print`
    override val message = "Message of Derived"
}

fun main() {
    val b = BaseImpl(10)
    val derived = Derived(b)
    derived.print()
    println(derived.message)
}

При компиляции ^ я получаю Type mismatch: inferred type is Base? but Base was expected.

Это все еще возможно с Kotlin?

Чтобы быть более подробным, я бы хотел, чтобы компилятор Kotlin генерировал переадресацию вызовов для упакованного impl (extWebChromeClient) в https://developer.android.com/reference/android/webkit/WebChromeClient следующим образом:

private WebChromeClient intWebChromeClient = new WebChromeClient()
  {
    @Override
    public void onReceivedTitle(WebView view, String title)
    {
      if (extWebChromeClient != null)
      {
        extWebChromeClient.onReceivedTitle(view, title);
      }
    }
 ...

1 Ответ

1 голос
/ 27 марта 2019

Вы можете сделать это самостоятельно, используя динамические прокси , хотя я бы не стал этого рекомендовать. Обратите внимание, что для не void методов нет способа требовать их переопределения. Приведенная ниже реализация просто генерирует для них исключения безоговорочно, но вы все равно можете вызывать их для ненулевых x.

inline fun <reified T : Any> nullableProxy(x: T?): T {
    val handler = InvocationHandler { _, method, args ->
        if (method.returnType == Void.TYPE) {
            if (x != null) {
                method.invoke(x, *(args ?: arrayOf()))
            }
        } else 
            throw UnsupportedOperationException("Non-void method")
    }

    return Proxy.newProxyInstance(
        T::class.java.classLoader,
        arrayOf(T::class.java),
        handler) as T
}

class Derived(b: Base?) : Base by nullableProxy(b)

Это также не будет работать так же хорошо, как реализация методов напрямую.

...