比较Kotlin中的两个选项

时间:2017-05-16 13:10:18

标签: kotlin

考虑一个id字段的类,该字段在存储在数据库中之前可能为null:

class IdableK<T : IdableK<T>> : Comparable<T> {    
    private var id : Long? = null
}

我正在尝试按如下方式实施compareTo方法:

    override fun compareTo(other: T): Int {
        if (id == null) {
            return -1;
        }

        if (other.id == null) {
            return 1;
        }

        return id!!.compareTo(other.id!!)
    }

这是一种正确的做法吗?会有一种简单的方法吗?

3 个答案:

答案 0 :(得分:6)

查看kotlin.comparisons package。例如您可以使用compareValues

class IdableK<T : IdableK<T>> : Comparable<T> {
    private var id: Long? = null

    override fun compareTo(other: T) = compareValues(id, other.id)
}

答案 1 :(得分:1)

这是不正确的。如果您有两个实例,其ID设置为null,则当您在其上调用-1时,两个实例都将返回compareTo(other),而如果其中一个返回-1,则另一个实例将返回1 {1}}正确实施。我不确定是否有可能基于可空属性实现compareTo是有意义的,但我无法想象。也许你有更好的方法吗?

此外,您应该避免使用非空断言(!!)。由于您正在使用var s,因此其他线程可能会将值更改为null,这样即使您之前执行了空检查,该值现在为null并且!!抛出。相反,您应该将两个ID存储在局部变量中,并检查这些值是否为null

如果你绝对必须使用compareTo,我会这样做:

override fun compareTo(other: T): Int {
    val thisId = id
    val otherId = other.id
    if (thisId == null && otherId == null) return 0
    if (thisId == null && otherId != null) return -1
    if (thisId != null && otherId == null) return 1

    // thisId and otherId are now smart cast to Long
    return thisId.compareTo(otherId)
}

答案 2 :(得分:0)

这是一个简单的方法:

override fun compareTo(other: T) :Int {
    return id?.compareTo(other.id ?: return 1) ?: -1
}

然而,这段代码对新手kotlin程序员来说非常不友好。它涉及太多魔法,使它看起来像scala。这三个问号让人感到困惑,至少他们必须思考一两分钟才能意识到这个简约的单行内容正在发生什么。我还是喜欢你的版本。它更冗长,但更清楚。

我真的很担心对称问题。这很重要,并不仅仅是一个设计问题。如果你不比较可空的属性,就不会有这个编程难题。它只是override fun compareTo(other: T) = id.compareTo(other.id)。简单,清晰,没有误导性。

我宁愿抛弃所有的空检查代码,只使用那些空的断言。因为在完全初始化之前,大多数情况下你不会比较那些东西。如果这些断言失败,则意味着发生了非常糟糕的事情。

哦,顺便说一句,我不知道你的项目,如果它遇到了你必须比较可空属性的罕见情况,我想你可以编写一个特殊版本的Comparator来考虑空值而不是投掷NPE。不要搞乱自然秩序。