В Котлин я пытаюсь скомпилировать следующее:
Следующий код не компилируется, потому что требуется тип: fun getMapper(animalType: AnimalType): Printer
Я пытался использовать <Any>
или <*>
но не добился успеха. Может кто-нибудь помочь?
(легко увидеть ошибку, скопировав код ниже на https://try.kotlinlang.org)
enum class AnimalType { CAT, DOG } class Dog class Cat interface Printer<in T> { fun mapToString(input: T): String } class DogPrinter : Printer<Dog> { override fun mapToString(input: Dog): String { return "dog" } } class CatPrinter : Printer<Cat> { override fun mapToString(input: Cat): String { return "cat" } } private fun getMapper(animalType: AnimalType): Printer { return when(animalType) { AnimalType.CAT -> CatPrinter() AnimalType.DOG -> DogPrinter() } } fun usage_does_not_compile() { getMapper(AnimalType.DOG) .mapToString(5) }
Я немного изменил код. getMapper
функция getMapper
в общий тип getMapper
, что делает вызов довольно читаемым в getMapper<Dog>()
.
Читайте о reified
здесь: Что действительно делает ключевое слово reified в Kotlin?
private inline fun <reified T> getMapper(): Printer<T> { when (T::class) { Cat::class -> return CatPrinter() as Printer<T> Dog::class -> return DogPrinter() as Printer<T> } throw IllegalArgumentException() } fun main(args: Array<String>) { println(getMapper<Dog>().mapToString(Dog())) println(getMapper<Cat>().mapToString(Cat())) }
Оверенная вещь даже не нужна на самом деле, но делает клиентскую сторону более читаемой. Кроме того, вы также можете передать класс в качестве аргумента функции getMapper
. Действительно важная часть состоит в том, чтобы сделать этот общий . Непроверенные броски не очень круты, но, похоже, здесь безопасны.
У Kotlin нет сырых типов, поэтому вы не можете вернуть Printer
из getMapper
. Вы можете вернуть Printer<*>
, сделать getMapper
generic или изменить структуру наследования, чтобы иметь общий супер-тип.
Возвращаемый Printer<*>
работает нормально. Но на самом деле это не полезно, потому что вы не можете вызвать mapToString(Dog())
(я предполагаю, что mapToString(5)
– это опечатка), и это хорошо: если он скомпилирован тогда
getMapper(AnimalType.CAT).mapToString(Dog())
также должен был бы скомпилироваться, поскольку тип возвращаемого значения может зависеть только от типа аргумента, а не от значения , а AnimalType.CAT
и AnimalType.DOG
имеют тот же тип. Есть некоторые языки, которые позволяют это, но Котлин не является одним из них.