Kotlin:一元加/减运算符对数字做了什么?

时间:2016-09-09 07:40:04

标签: operators kotlin

我在Kotlin中注意到,所有数字类型都已经定义了unaryPlusunaryMinus运算符。

这些运营商的目的是什么?它们是否以某种方式与incdec的前缀形式相关联?

3 个答案:

答案 0 :(得分:9)

其他人已经定义了unaryMinusunaryPlus的基本含义,实际上在数字类型上,它们实际上甚至可能不被称为函数。例如,编码+xx.unaryPlus()会生成相同的字节码(其中x的类型为Int):

ILOAD 1
ISTORE 2

代码-xx.unaryMinus()生成相同的字节码:

ILOAD 1
INEG
ISTORE 2

但是还有更多这样的事情......

那么为什么编译器甚至会为+x生成任何内容?有些人会说+xx.unaryPlus()没有做任何事情,-xx.unaryMinus()只会撤消这个标志。这是不正确的。在Java中它更复杂,因为它可能涉及扩展和拆箱,请参阅Unary Numeric Promotion,它解释了这些运算符的全部后果。这会对盒装值和小于Int的类型产生影响。对于ShortByte类型的值,这些运算符将返回类型为Int的新的未装箱值。由于两个运算符都具有更多隐藏功能,因此即使您不认为+x做任何事情,它们也必须生成字节码。顺便说一句,这类似于C语言所做的,它被称为Usual Arithmetic Conversions

因此,此代码无效:

val x: Short = 1
val y1: Short = +x              // incompatible types
val y2: Short = x.unaryPlus()   // incompatible types
val z1: Short = -x              // incompatible types
val z2: Short = x.unaryMinus()  // incompatible types

在基本数值类型的这些数字情况下,它们只是编译器魔术,允许将这些运算符的概念等同于您可能希望在其他类中重载的运算符函数。

用于其他用途,例如运算符重载...

但它们不仅仅是数学用途,而且可以作为运算符用于任何类。 Kotlin将运算符公开为函数,以便您可以对包含unaryMinusunaryPlus的特定运算符集应用operator overloading

我可以使用它们来定义我自己或现有类的运算符。例如,我有一个Set<Things>,其中Things是一个枚举类,还有一个unaryMinus()运算符来否定有限选项集的内容:

enum class Things {
    ONE, TWO, THREE, FOUR, FIVE
}

operator fun Set<Things>.unaryMinus() = Things.values().toSet().minus(this)

然后我可以随时否定我的枚举:

val current = setOf(Things.THREE, Things.FIVE)
println(-current)       // [ONE, TWO, FOUR]
println(-(-current))    // [THREE, FIVE]

请注意,我必须使用修饰符operator声明我的扩展函数,否则这将无效。当您尝试使用运算符时,编译器会提醒您是否忘记了这一点:

  

错误:(y,x)Kotlin:&#39;运营商&#39;修改者需要在“一元明星”上进行修改。在&#39; com.my.favorite.package.SomeClass&#39;

答案 1 :(得分:6)

这些运算符是整数的符号。以下是一些例子:

+5调用5.unaryPlus()并返回5.

-5调用5.unaryMinus()并返回-5。

-(-5)调用5.unaryMinus().unaryMinus()并返回5.

答案 2 :(得分:3)

这些运营商的目的是能够写下:

val a = System.nanoTime()
val b = -a // a.unaryMinus()
val c = +b // b.unaryPlus()

它们与++ / inc-- / dec运营商没有直接关系,但它们可以结合使用。

请注意,以下表达式不同:

--a // a = a.dec()
-(-a) // a.unaryMinus().unaryMinus()