Перегрузка расширения параметров связанного типа Kotlin - PullRequest
0 голосов
/ 03 июля 2018

Можно ли перегрузить функции расширения на основе параметров их связанного типа? Например:

abstract class BaseActivity : AppCompatActivity() {

    fun <T : Drawable> Int.get(): T? 
        = ContextCompat.getDrawable(this@BaseActivity, this@get) as T?
    fun <T : View> Int.get(): T 
        = findViewById(this)

}

Пример использования:

R.id.webView.get<WebView>() // finds webView
R.drawable.image.get<Drawable>() // gets drawable from resources

(код Android не имеет отношения к проблеме, это именно то, что у меня было)

Но это дает мне ошибку:

Conflicting overloads: public fun <T : Drawable> Int.get(): T? defined in xxx.BaseActivity, 
public final fun <T : View> Int.get(): T defined in xxx.BaseActivity

Разве это не возможно?

Ответы [ 3 ]

0 голосов
/ 03 июля 2018

Можно ли перегрузить функции расширения на основе параметров их связанного типа?

Вообще-то да. Проблема заключается в том, что параметры появляются только в возвращаемых типах, а правила Java (которым в этом отношении следует Kotlin) не допускают перегрузку методов на основе их возвращаемых типов, потому что возвращаемые типы не используются для разрешения перегрузки. Это решение было принято до того, как дженерики появились в Java, потому что тогда компилятор никогда не мог выбрать более конкретный метод. Впоследствии это могло быть пересмотрено, но не было.

Если бы у вас был T параметр , он бы работал.

0 голосов
/ 11 мая 2019

Нормальный способ разрешения конфликта объявлений платформы с использованием @JvmName здесь не сработает: Kotlin допускает перегрузку по типам значений параметров, а не по границам параметров типов.

Это (безобразно) можно обойти, добавив параметры бесполезных значений с (так же бесполезными) значениями по умолчанию.

// unchanged
fun <T : Drawable> Int.get(): T? =
        ContextCompat.getDrawable(this@BaseActivity, this@get) as T?

// added a parameter
fun <T : View> Int.get(dummy: Nothing? = null): T =
        findViewById(this)

Некоторые несвязанные заметки:

  • такие маленькие методы должны быть inline, особенно те, которые имеют значения по умолчанию для параметров
  • findViewById можно заменить на Расширения Kotlin для Android
  • Anko библиотека имеет много полезных расширений и ярлыков, в том числе для извлечения ресурсов и даже построения макетов из кода без XML
0 голосов
/ 03 июля 2018

Две функции будут скомпилированы в одну и ту же сигнатуру функции после стирания обобщенных элементов.

Например, это может выглядеть так:

@NotNull
public final String get() {
  ...
}

Компилятор не может знать, какую функцию вызывать.

Решением этой проблемы могут быть параметры типа reified.

    interface Some
    interface Other

    inline fun <reified T> get() = when (T::class) {
        Some::class -> "hey"
        Other::class -> null
        else -> throw UnsupportedOperationException()
    }

Однако тогда вы должны снять ограничения по типу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...