2

我试图通过构建扩展内置类的非常简单的方法和属性获取器来了解有关 Kotlin 抽象类扩展和泛型的更多信息。我基本上是成功的,但我被 Number 类难住了。我的测试属性Number.sgn旨在返回 Number 的任何子类的符号(1 或 -1 作为 Int)。为简单起见,负数应该返回 -1,而正数和 0 应该返回 1。我对这个方法的用例不是特别感兴趣,但为了理解如何编写这样简单的东西——以及为什么我的代码会生成错误。我的模块中唯一的导入是kotlin.text.*,我收到的错误消息确实提到了那里的冲突。我只是不明白它为什么会发生冲突以及如何克服它——尽管我在猜测它

我首先编写了扩展 Int 类的代码,效果很好:

inline val Int.sgn get() = if (this<0) -1 else 1 // sign of number

然后我尝试概括并将其移至 Number 类,如下所示:

inline val Number.sgn get() = if (this<0) -1 else 1 // doesn't compile

编译错误如下:

unresolved reference. None of the following candidates is applicable because of receiver type mismatch: public fun String.compareTo(other: String, ignoreCase: Boolean = ...): Int defined in kotlin.text inline fun Number.sgn() = if (this<0) -1 else 1 ^

然后我尝试了一种不同的方法,使用泛型:

inline val <T:Number> T.sgn get() = if (this<0) -1 else 1

我从编译器收到了同样的错误:

error: unresolved reference. None of the following candidates is applicable because of receiver type mismatch: public fun String.compareTo(other: String, ignoreCase: Boolean = ...): Int defined in kotlin.text inline val <T:Number> T.sgn get() = if (this<0) -1 else 1 ^

谁能帮我理解为什么存在类型不匹配,以及为什么kotlin.text在这里很重要?有没有一种方法可以用来克服这个问题并让这个属性获取器应用于 Number 的所有子类?(再一次,我知道这不是一个有意义的用例,而是一个简化的示例,可以帮助我理解其背后的原理。)提前感谢任何人都可以提供的任何建议......

4

1 回答 1

1

您的第一个函数有效,因为Intimplements Comparable<Int>,这就是<运算符被翻译成的。但是,如果您查看Number该类,您会发现它只有用于转换到其各种子类的函数——它没有实现Comparable,因此,您不能<在其上使用运算符。

您可以做的是将您的转换NumberDouble第一个,然后查看它是否为负:

inline val <T : Number> T.sgn 
    get() = if (this.toDouble() < 0) -1 else 1

compareTo您还可以通过将函数实现Number为扩展来使您的原始代码(有或没有泛型)工作:

operator fun Number.compareTo(other: Number) = this.toDouble().compareTo(other.toDouble())

请注意,将所有内容转换为Double可能会导致精度下降。

于 2017-10-06T04:45:20.617 回答