Kotlin вызывает перегруженную функцию по типу параметра (когда известен только тип интерфейса) - PullRequest
1 голос
/ 08 ноября 2019

Наша кодовая база имеет интерфейс с большим количеством реализаций. Они сериализуются, хранятся и десериализуются. Когда один десериализован, мы вызываем функцию, которая принимает тип интерфейса, который затем имеет гигантское условие when, которое ветвится на основе определенного типа, то есть

   when (t) {
      is SubType1 -> ...
      is SubType2 -> ...
      is SubType44 -> ...
   }

Это грубое и добавляет высокую сложность функции,Одна из возможностей - переместить действие, которое мы хотим выполнить, в сами фактические реализации, поэтому мы можем просто вызвать t.doAction () и исключить предложение when. Это нормально, но эта конкретная логика на самом деле не относится к реализациям (по причинам), поэтому было бы лучше иметь возможность вместо этого вызывать перегруженные функции с типом параметра, а kotlin выяснить, какой из них вызывать, основываясь на типе реализации. ,К сожалению, это не похоже на это;мы получаем «Ни одна из следующих функций не может быть вызвана с предоставленными аргументами».

Есть ли здесь шаблон, который мы могли бы использовать, который бы удовлетворял компилятору?

Придуманный пример ниже. i1 - это Int внутри, но компилятор не может этого увидеть, потому что он напечатан как интерфейс, то есть Number.

    fun test() {
        val e = Example()

        val i1 = 123 as Number
        val i2 = 123.0

        e.sqrt(i1)
        e.sqrt(i2)
    }

    class Example {

        fun sqrt(i: Int) {

        }

        fun sqrt(i: Double) {

        }
   }
}

1 Ответ

0 голосов
/ 08 ноября 2019

Вы можете создать карту общения. Функция останется прежней с новыми реализациями, и только карта станет больше:

val map : Map<KClass<*>, (Any) -> Unit> = mapOf(
  SubType1::class to { /*SubType1 implementation*/ },
  SubType2::class to { /*SubType2 implementation*/ },
  ...
)

fun <T> execute(item: T) {

  map[item::class]?.invoke(item) ?: error("Case not implemented")

}

Если у вас много строк реализации для каждого случая и / или вы хотите провести элегантное тестирование, вы можете создать класс длякаждый случай и проверить его отдельно:

interface ClassDesicion<T> {
   fun execute(item: T) : Unit
}

val map : Map<KClass<*>, ClassDesicion<*>> = mapOf(
  SubType1::class to SubType1Implementation(),
  SubType2::class to SubType2Implementation(),
  ...
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...