Inferring параметр типа класса по умолчанию
У меня есть класс с конструктором объявлен так
class Facade<T : SuperClass>(
val kClass: KClass<in T> = SuperClass::class
)
Это делается так, чтобы разработчику не нужно было указывать SuperClass, если он хочет использовать его вместо подкласса. Причина даже для отправки типа класса такова, что разработчику не нужно указывать тип в угловых скобках.
Но теперь приходит проблема. Создание экземпляра, как показано ниже, говорит о том, что для вывода параметра T недостаточно информации, что приводит к необходимости помещать класс в угловые скобки.
Facade()
Но так как значением по умолчанию является SuperClass, то kotlin должен иметь возможность выводить параметр T как SuperClass. Что я не так думаю?
Спасибо
TL;DR:
Facade(SubClass:class) // working
Facade(SuperClass:class) // working, but don't want (superclass is default)
Facade<SuperClass>() // working, but don't want angle brackets <>
Facade() // not working, cannot infer T type from default, why?
2 ответа
Для Facade()
быть эквивалентным Facade(DerivedClass::class)
параметр конструктора по умолчанию должен быть объявлен как val kClass: KClass<in T> = T::class
, Однако использовать T::class
T
параметр типа должен быть reified
, Параметр типа может быть реализован только во встроенных функциях, но не в конструкторах.
Чтобы обойти эту проблему, вы можете объявить фабричную функцию, которая делегирует конструктору, вот так:
inline fun <reified T : SuperClass> Facade(): Facade<T> = Facade(T::class)
Это позволяет использовать его как, например:
val derivedFacade:Facade<DerivedClass> = Facade()
Обратите внимание, что если вы хотите использовать SuperClass
в качестве параметра по умолчанию для T
вам нужно будет объявить другой метод фабрики, используя другое имя, например:
fun SuperFacade(): Facade<SuperClass> = Facade()
Это необходимо, так как если бы мы объявили @JvmName("SuperFacade") fun Facade() = Facade(SuperClass::class)
компиляция будет соответствовать ему всякий раз, когда мы не предоставляем параметры типа. Это, в свою очередь, не поддается выводу типа из derivedFacade
пример.
Вы можете решить свою проблему, сняв угловые скобки и изменив тип конструктора. Просто используйте этот конструктор:
class Facade(val kClass: KClass<*> = SuperClass::class)
Все эти звонки работают
Facade(SubClass:class)
Facade(SuperClass:class)
Facade()