Котлин: что делают унарные операторы плюс/минус на числах?

Я заметил в Котлине, что там уже определены 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()