Котлин: что делают унарные операторы плюс/минус на числах?
Я заметил в Котлине, что там уже определены unaryPlus
и unaryMinus
операторы для всех типов чисел.
какова цель этих операторов? Связаны ли они каким-либо образом с префиксными формами inc
и dec
?
3 ответов
другие определили основное значение 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
.
я мог бы использовать их для определения операторов для моих собственных или существующих классов. Например у меня есть 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
или это не будет работать. Компилятор напомнит вам, если вы забудьте об этом при попытке использовать оператор:
Error: (y, x) Kotlin: модификатор 'operator' требуется для 'unaryMinus' в 'com.мой.любимый.пакет.SomeClass'
эти операторы являются знаками чисел. Вот несколько примеров:
+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()