В Котлине можно объявить общий тип функции как возвращаемый тип функции?
То, что я хочу достичь, будет выглядеть так на Java:
interface Factory { static Factory INSTANCE = new FactoryImpl(); <T> T create(String name, Class<T> type); } class PrefixedFactory implements Factory { private final String prefix; PrefixedFactory(String prefix) { this.prefix = prefix; } @Override public <T> T create(String name, Class<T> type) { return Factory.INSTANCE.create(prefix + name, type); } }
(Обратите внимание, что в примере я обращаюсь к экземпляру Factory с использованием статического поля, чтобы избежать передачи общей функции в качестве параметра, что могло бы представлять свои проблемы в Котлине). Я хотел бы преобразовать префикс в функцию kotlin, но, как представляется, невозможно объявить общую функцию как возвращаемый тип:
fun prefixer(prefix: String): <T> (String, KClass<T>) -> T { TODO() }
Это, конечно, не компилируется. Мне кажется, что это ограничение по сравнению с функциональными интерфейсами Java. Есть ли способ сделать это или обходным путем?
Я хочу, чтобы функция фактического результата была общей. Если я сделаю
fun <T: Any> prefixer(prefix: String): (String, KClass<T>) -> T { TODO() }
как показывают текущие ответы; Я не получаю общую функцию, вместо этого получаю (String, KClass<Foo>) -> Foo
если я вызываю prefixer<Foo>("")
. Таким образом, эту функцию можно вызывать только с помощью Foo
, в то время как prefixer
фабричной функции в этом случае является общим, результата нет. Надеюсь, это устранит недоразумения.
Мой вариант использования находится в плагине Gradle, где я написал вспомогательный метод, подобный этому, который применяет некоторые значения по умолчанию для каждой созданной задачи:
val myPrefix = "..." val project: Project = <from context> fun <T: Task> String.task(type: KClass<T>, doConfig: T.() -> Unit) { project.tasks.create("$prefix$this", type.java, { it.doConfig() }) }
Обратите внимание, что проект приходит как закрытие. Теперь я хочу повторно использовать этого помощника в другом плагине, поэтому я хотел бы создать эту функцию, используя фабрику для разных экземпляров проекта.
Вы делаете это почти правильно. Вам нужно только определить общую часть функции prefixer
напрямую.
fun <T: Any> prefixer(prefix: String): (String, KClass<T>) -> T { TODO() }
В зависимости от вашей фактической реализации вы можете взглянуть на ключевое слово reified
.
Следующая строка компилирует:
fun <T : Any> prefixer(prefix: String): (String, KClass<T>) -> T = TODO()
Во-первых, общее замедление должно быть сразу после ключевого слова fun.
Затем он должен быть объявлен как тип Any. По умолчанию используется Any? но KClass принимает только Any.
Нет, это невозможно (насколько я знаю). Технический термин для такого типа – «тип более высокого типа», и очень немногие языки поддерживают их, на JVM я знаю только Scala.
Если кто-то задал мне тот же вопрос без интерфейса, например Factory
, я бы предложил создать именно этот интерфейс в качестве обходного пути.