【发布时间】:2016-09-09 07:40:04
【问题描述】:
我注意到在 Kotlin 中已经在所有数字类型上定义了 unaryPlus 和 unaryMinus 运算符。
这些运算符的目的是什么?它们是否以某种方式连接到inc 和dec 的前缀形式?
【问题讨论】:
我注意到在 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 中它更复杂,因为它可能涉及扩展和拆箱,请参阅Unary Numeric Promotion,它解释了这些运算符的全部后果。这会对小于Int 的装箱值和类型产生影响。对于Short 和Byte 类型的值,这些运算符将返回一个扩展为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 将运算符公开为函数,以便您可以将 operator overloading 应用于一组特定的运算符,包括 unaryMinus 和 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()
【讨论】:
fun main(){
var a = 34
var b = 56
println("Orignal value:"+ a)
println("Orignal value:"+ b
//The value will not change using .unaryPlus() will generate bytecode
println("After unary plus:" + a.unaryPlus())
//The value will invert the sign using .unaryMinus() will generate bytecode
println("After unary minus:" + b.unaryMinus())
}
Solution:
Orignal value:34
Orignal value:56
After unary plus:35
After unary minus:-55
【讨论】: