Kotlin函数语法

我正在做Kotlin Koans测试,以便熟悉Kotlin。 在某个测试中,我必须重写compareTo方法。 在第一种情况下,一切都按预期工作

 data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) { operator fun compareTo(other: MyDate)= when { year != other.year -> year - other.year month != other.month -> month - other.month else -> dayOfMonth - other.dayOfMonth } } 

现在在第二种情况下,我正在写compareTo有点不同,我得到了大量的编译错误。

 data class MyDate(val year: Int, val month: Int, val dayOfMonth: Int) { operator fun compareTo(other: MyDate){ when { year != other.year -> return year - other.year month != other.month -> return month - other.month else -> return dayOfMonth - other.dayOfMonth } } } 

首先,在运营商关键字,我得到一个错误:

‘operator’修饰符不适用于这个函数:必须返回Int

并在我得到的回报

types不匹配:推断types是Int,但Unit是预期的

我不明白为什么这些错误发生,因为第一个实现返回相同的Int

这是因为=作为{ return X } 这只适用于函数定义 。 所以这意味着在第一个例子中你的代码就是这个

 operator fun compareTo(other: MyDate):Int { return when { year != other.year -> year - other.year month != other.month -> month - other.month else -> dayOfMonth - other.dayOfMonth } } 

但是在你的第二个例子中,你不会返回when的结果。 这会导致编译器感到困惑,因为它期望您返回一个Int但是您返回Unit (相当于Java的void

所以你所要做的就是向它添加一个明确的返回types( fun X(/*args*/) : Int或其他适用的types)

在第一个示例中, compareTo(MyDate)的返回types被推断为Int因为whenexpression式的所有分支都返回一个Int

在你的第二个例子中, compareTo(MyDate)的返回types是Unit 。 由于你的函数具有块体,所以返回types必须明确指定(除非它们打算让它们返回Unit )。 所以, Unit在这里应该是返回types,但是when你的expression式是Int when ,返回types是可以被推断出来的。 这就是为什么你会得到这个错误:

types不匹配:推断types是Int,但Unit是预期的

下面是用块体明确定义函数的返回types的官方解释 :

块体的函数必须总是明确地指定返回types,除非它们打算让它们返回Unit, 在这种情况下它是可选的 。 Kotlin不推断块体的函数返回types,因为这样的函数可能在主体中有复杂的控制流,返回types对读者(有时甚至是编译器)也是不明显的。

因此,声明compareTo(MyDate)的正确方法是指定函数的返回types(如果它包含块体):

 operator fun compareTo(other: MyDate): Int { when { year != other.year -> return year - other.year month != other.month -> return month - other.month else -> return dayOfMonth - other.dayOfMonth } } 

由于比较运算符需要返回一个Int ,所以同时解决了另一个错误。

除了@Mibac的答案:你可以缩短一点:

 operator fun compareTo(other: MyDate) = when { year != other.year -> year - other.year month != other.month -> month - other.month else -> dayOfMonth - other.dayOfMonth }