2017-10-06 50 views
1

我想通过构建非常简单的方法和扩展内置类的属性获取器来了解Kotlin抽象类扩展和泛型的更多信息。我大部分都是成功的,但是我被Number类难住了。我的测试属性Number.sgn旨在返回Number的任何子类的符号(1或-1作为Int)。为了简单起见,负数应该返回-1,而正数和0应该返回1.我对这种方法的用例并不特别感兴趣,但为了理解如何写这样简单的东西 - 以及为什么我的代码生成错误它。我的模块中唯一的导入是kotlin.text.*,并且我收到的错误消息确实指向那里的冲突。我只是不理解它为什么会发生冲突,以及如何克服它 - 虽然我猜这是一个新手的错误。如何扩展Kotlin Number类或使用泛型来创建一个简单的属性getter,它将在所有Number子类上运行?

我第一次写的代码来扩展int类,它工作得很好:

inline val Int.sgn get() = if (this<0) -1 else 1 // sign of 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在这里很重要?有没有一种方法可以用来解决这个问题,并让这个属性getter应用于Number的所有子类? (同样,我知道这是不是一个有意义的使用情况,而是一个简单的例子,以帮助我理解这背后的原理。)在此先感谢您的任何意见任何人都可以给...

回答

1

你的第一个功能,因为工作Int implements 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可能导致丢失精度。

+0

感谢您的快速/彻底的答案。一旦你开始关注compareTo的路径,我试图研究如何让Kotlin调用具体的Number类的compareTo,而不是在Number中寻找compareTo的实现。我调整了东西,直到我结束了:'inline val T.sgn其中T:Number,T:Comparable get()= if(this <(0 as T))-1 else 1'它有效,但我'米仍然不确定我是否理解我是否可以在不使用泛化技术的情况下使用泛型,以及/或者是否实质性地实现物化效果。再次感谢! – sirksel

相关问题