Kotlin generi c преобразователь интерфейса - PullRequest
1 голос
/ 17 июня 2020

Я пытаюсь создать преобразователь, который с учетом некоторого контекста домена возвращает реализацию универсального интерфейса c. Код следующий (абстрагированный домен):

interface Interface<T>

class StringImplementation: Interface<String>

class BooleanImplementation: Interface<Boolean>

class Resolver {

    fun <T : Any> resolve(implementation: String): Interface<T> {
        return when (implementation) {
            "string" -> StringImplementation()
            "boolean" -> BooleanImplementation()
            else -> throw IllegalArgumentException()
        }
    }

}

Этот фрагмент мне нравится, но компилятор жалуется, потому что Type missmatch: Required: Interface<T> Found: StringImplementation в строке 11 и Type missmatch: Required: Interface<T> Found: BooleanImplementation в строке 12.

Почему это проблема? Я хотя установка <T : Any> в контракте метода позволила бы вернуть реализацию любого типа. Ограничение здесь состоит в том, что тип возвращаемого значения метода resolve должен быть Interface<T>, замена его на Interface<*> заставит компилятор отключиться, но это не то, что нам нужно.

Ответы [ 3 ]

1 голос
/ 17 июня 2020

Компилятор не может знать, соответствует ли T переменной implementation. Даже если implementation равно string, T может быть другого типа, чем String. Таким образом, вы можете либо стереть тип generi c, как упомянутый @Neo, либо вам нужно привести тип возвращаемого значения.

interface Interface<T>

class StringImplementation: Interface<String>

class BooleanImplementation: Interface<Boolean>

class Resolver {

    inline fun <reified T : Any> resolve(): Interface<T> {
        return when (T::class) {
            String::class -> StringImplementation() as Interface<T>
            Boolean::class -> BooleanImplementation() as Interface<T>
            else -> throw IllegalArgumentException()
        }
    }
}

Для большей безопасности типов вы можете использовать переопределенный параметр и использовать его для определения типа. (Учтите, что кастинг все еще необходим)

1 голос
/ 17 июня 2020

Я, хотя установка <T : Any> в контракте метода позволила бы вернуть реализацию любого типа.

Нет, это означает, что имеет для возврата реализация любого типа вызывающая сторона запрашивает . Например, в примере Anime sh Sahu, resolve<Boolean>("string") должен возвращать Interface<Boolean>, но ваша реализация resolve вернет StringImplementation. Конечно, это также может быть resolve<File>("string") et c.

позволяет возвращать реализацию любого типа

который вызываемый метод выбирает ровно Interface<*>.

1 голос
/ 17 июня 2020

TL; DR

Функция может иметь ровно 1 тип возвращаемого значения, но ваша функция имеет 2 разных типа возвращаемого значения.

Работает только это:

interface Interface<T>

class StringImplementation: Interface<String>

class BooleanImplementation: Interface<Boolean>

class Resolver {

    fun resolve(implementation: String): Interface<*> { // <-- star
        return when (implementation) {
            "string" -> StringImplementation()
            "boolean" -> BooleanImplementation()
            else -> throw IllegalArgumentException()
        }
    }

}

Пояснение

С точки зрения определения функции, он должен иметь явный, ясный тип возврата. Interface<T> говорит, что это должно быть что-то расширяющее Interface и явный тип T , конкретная реализация которого может быть известна по началу выполнения функции.
Там в вашем коде нет способа узнать, что будет T, когда вы позвоните resolve. Как еще вы вообразите, что функция будет знать, что она вернет?!

Сокращенно: функция может иметь ровно 1 тип возвращаемого значения, но ваша функция имеет 2 разных типа возвращаемых значений (Interface<String> / Interface<Boolean>) .

Продолжайте читать здесь , если хотите углубиться в дженерики и получить более подробное техническое описание.

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