Kotlin 对泛型集合进行排序

问题描述 投票:0回答:1

我有一些用于过滤查询数据的内联函数,如下所示:

inline fun <reified T> findByFilterFunc(filter: String, em: EntityManager, offset: Int, limit: Int, sortName: String?, sortDirection: String?): List<T> {
    val bt = SimpleBuilderTools()
    val rootNode = RSQLParser().parse(filter)

    val builder = em.criteriaBuilder
    val query = initQueryFunc<T, T>(builder, filter)
    val root = query.getRootByType(T::class.java)

    query.where(PredicateBuilderObj.createPredicate(rootNode, em, bt, root, query))

    query.select(root)

    if (sortName !== null) {
        val expression = root.get<Expression<*>>(sortName)
        query.orderBy(if (sortDirection == "ASC") builder.asc(expression) else builder.desc(expression))
    }
    return em.createQuery(query).setFirstResult(offset * limit).setMaxResults(limit).resultList
}

但是我可以在 SQL 查询中使用排序,因为我的方言不支持它。我尝试使用 kotlin

sortedBy {}
来查询结果,如下所示:

val prop = T::class.java.javaClass.kotlin.declaredMemberProperties.find { it.name == sortName }
    return em.createQuery(query).setFirstResult(offset * limit).setMaxResults(limit).resultList.sortedBy(prop)

但是这是无效代码。如何对具有泛型类型的集合进行排序?

我认为我需要使用自定义比较器,但我不明白如何对未知的泛型类型执行此操作

kotlin sorting generics collections
1个回答
0
投票

TL;DR 我认为 Kotlin 没有足够的信息来实现未知类型的比较

T

以下是对您的代码的一些更改:

首先你有

val prop = T::class.java.javaClass.kotlin.declaredMemberProperties.find { it.name == sortName }

返回

KProperty1<Class<T>, *>?

我想你需要这个:

val prop: KProperty1<T, *>? = T::class.declaredMemberProperties.find { it.name == sortName }

然后就可以获取属性的运行时值了:

requireNotNull(prop)
prop.get(...instance...)

然后你实现一个像这样的内联自定义比较器

        return em.createQuery(query)
            .setFirstResult(offset * limit)
            .setMaxResults(limit)
            .resultList
            .sortedWith { o1: T, o2: T ->
               val v1: Any? = prop.get(o1)
               val v2: Any? = prop.get(o2)
               //how to compare?
               v1.toString().compareTo(v2.toString())
        }

问题是类型信息不可用,并且由于

Any
未实现
compareTo
你如何知道一般如何排序?

您可能会问自己的问题...数据库引擎如何排序?如果它是具有强类型列的 RDMS,则引擎在运行时知道要使用什么排序/排序规则。如果它是非结构化存储,例如 Mongo,它有一个策略来对它支持的相对较少类型进行排序。

您将在您的应用程序中提供多少种类型的排序?一旦您知道运行时类型,并且如果您要使用此实用程序的类型数量有限,我想您可以编写自定义比较器(

if v1 is Number
,然后您就会知道该怎么做)或回退到
toString().compareTo

但是,如果您可以首先对

T
施加更严格的约束...它必须像这样实现
Comparable

inline fun <reified T : Comparable<T>> findByFilterFunc(...

然后你就可以写了

        .sortedWith { o1: T, o2: T ->
            val v1 = prop.get(o1) as T
            val v2 = prop.get(o2) as T
            v1.compareTo(v2)
        }
© www.soinside.com 2019 - 2024. All rights reserved.