Kotlin:通用函数作为返回类型?

时间:2017-10-23 08:34:19

标签: function generics lambda kotlin

在Kotlin中,是否可以将泛型函数类型声明为函数的返回类型?

我想要实现的目标在Java中看起来像这样:

case class Product(
    @(QuerySqlField @field)(index = true) version: Long,
    attributes: java.util.Map[String, String]
)

object Main {
    val TestProduct = Product(2L, Map("pid" -> "123", "foo" -> "bar", "baz" -> "quux").asJava)

    def main(args: Array[String]): Unit = {
        Ignition.setClientMode(true)
        val ignite = Ignition.start()
        val group = ignite.cluster.forServers

        val cacheConfig = new CacheConfiguration[String, Product]
        cacheConfig.setName("inventory1")
        cacheConfig.setIndexedTypes(classOf[String], classOf[Product])
        val cache = ignite.getOrCreateCache(cacheConfig)

        cache.put("P123", TestProduct)

        val query = new SqlQuery(classOf[Product], "select * from Product where version > 1")
        val resultSet = cache.query(query)
        println(resultSet)
    }
}

(注意,在示例中,我使用静态字段访问Factory实例,以避免将泛型函数作为参数传递,这将在Kotlin中呈现自己的问题)。 我想将前缀转换为kotlin函数,但似乎不可能将泛型函数声明为返回类型:

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);
    }
}

这当然不能编译。在我看来,与Java的功能接口相比,这是一个限制。有没有办法实现这一目标,或者解决方法?

(编辑)澄清

我希望实际的结果函数是通用的。如果我做

fun prefixer(prefix: String): <T> (String, KClass<T>) -> T { TODO() }

目前的答案表明;我没有获得通用函数,而是在调用fun <T: Any> prefixer(prefix: String): (String, KClass<T>) -> T { TODO() } 时获得(String, KClass<Foo>) -> Foo。因此,只能使用prefixer<Foo>("")调用该函数,而在这种情况下,工厂函数Foo是通用的,结果不是。我希望能够消除误解。

我的用例是在Gradle插件中,我写了一个类似于这个的帮助方法,它将一些默认值应用于每个创建的任务:

prefixer

请注意,该项目是封闭式的。现在我想在不同的插件中重用该帮助器,所以我想使用工厂为不同的项目实例创建这个函数。

4 个答案:

答案 0 :(得分:3)

你几乎正确地做到了。您只需要直接在prefixer函数中定义通用部分。

fun <T: Any> prefixer(prefix: String): (String, KClass<T>) -> T { TODO() }

根据您的实际实施情况,您可以查看reified关键字。

答案 1 :(得分:2)

以下行确实编译:

fun <T : Any> prefixer(prefix: String): (String, KClass<T>) -> T = TODO()

首先,通用减速应该在fun关键字之后。

然后必须将其声明为Any类型。默认是Any?但KClass只接受Any。

答案 2 :(得分:0)

不,这是不可能的(据我所知)。这种类型的技术术语是“更高级的类型”,很少有语言支持它们,在JVM上我只知道Scala。

如果有人在没有像REGISTER_OP("CsvIter") .Input("data_file: string") .Output("labels: float32") .Output("signs: int64") .Attr("input_schema: list(string)") .Attr("feas: list(string)") .Attr("label: string = 'label' ") .Attr("batch_size: int = 10000") .SetIsStateful(); // Add this line. 这样的界面的情况下向我提出同样的问题,我建议您准确创建此界面作为解决方法。

答案 3 :(得分:0)

尽管我对阅读@Alexey的答案感到失望,但我发现利用Kotlin的操作员的优势,可以简化工作流程。以下内容使它在使用时更像是lambda:

private class Prefixer(private val: String) {
    operator fun <T> invoke(name: String, type: Class<T>): T {
        TODO()
    }
}

要使用它:

val createMy = Prefixer("MyPrefix")
val result = createMy("Configuration", Configuration::class.java)

如有必要,可以随时用KClass替换。实际上,我将其用于稍微不同的目的。