Kotlin:单数加/减运算符在数字上做什么?
我已经注意到在Kotlin中已经定义了所有数字类型的unaryPlus
和unaryMinus
操作符。
这些运营商的目的是什么? 它们是否以某种方式连接到inc
和dec
的前缀形式?
其他人已经定义了unaryMinus
和unaryPlus
的基本含义,而实际上在数字类型中,它们实际上甚至可能不被称为函数。 例如,编码+x
或x.unaryPlus()
生成相同的字节码(其中x
是Int
类型):
ILOAD 1 ISTORE 2
代码-x
或者x.unaryMinus()
生成相同的字节码:
ILOAD 1 INEG ISTORE 2
但是还有更多这样的…
那为什么编译器甚至会为+x
生成任何东西呢? 有些人会说+x
和x.unaryPlus()
不会做任何事情,而-x
和x.unaryMinus()
只会颠倒符号。 这是不正确的。 在Java中它更复杂,因为它可能涉及到扩大和拆箱,请参阅说明这些操作员的全部后果的一元数字升级 。 这对盒装值和类型比Int
小。 对于Short
和Byte
类型的值,这些运算符将返回一个新的类型为Int
装箱值。 而且由于两个操作符都有这个更隐藏的功能,所以即使你不认为+x
做任何事情,它们也必须生成字节码。 顺便说一下,这与C语言的功能类似,称为“ 常用算术转换” 。
所以这个代码是无效的:
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将操作符公开为函数,以便您可以将操作符重载应用于包含unaryMinus
和unaryPlus
的特定操作符unaryPlus
。
我可以使用这些来为我自己或现有的类定义运算符。 例如,我有一个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:“com.my.favorite.package.SomeClass”中的'unaryMinus'需要'operator'修饰符
这些运营商是整数的标志。 这里有些例子:
+5
调用5.unaryPlus()
并返回5。
-5
调用5.unaryMinus()
并返回-5。
-(-5)
调用5.unaryMinus().unaryMinus()
并返回5。
这些运营商的目的是能够写:
val a = System.nanoTime() val b = -a // a.unaryMinus() val c = +b // b.unaryPlus()
它们与++
/ inc
和--
/ dec
运算符没有直接关系,但是它们可以结合使用。
请注意,以下表达式是不同的:
--a // a = a.dec() -(-a) // a.unaryMinus().unaryMinus()