# Kotlin 的运算符

> 原文： [http://zetcode.com/kotlin/operators/](http://zetcode.com/kotlin/operators/)

在本教程中，我们将介绍 Kotlin 运算符。 我们展示了如何使用运算符创建表达式。

运算符是特殊符号，表示已执行某个过程。 编程语言的运算符来自数学。 程序员处理数据。 运算符用于处理数据。 操作数是运算符的输入（参数）之一。

表达式是根据操作数和运算符构造的。 表达式的运算符指示将哪些运算应用于操作数。 表达式中运算符的求值顺序由运算符的优先级和关联性确定。

一个运算符通常有一个或两个操作数。 那些仅使用一个操作数的运算符称为一元运算符。 那些使用两个操作数的对象称为二进制运算符。

某些运算符可以在不同的上下文中使用。 例如，`+`运算符可以在不同的情况下使用：它添加数字，连接字符串或指示数字的符号。 我们说运算符是重载。

## Kotlin 标志运算符

有两个符号运算符：`+`和`-`。 它们用于指示或更改值的符号。

`KotlinSignOperatorsEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    println(2)
    println(+2)
    println(-2)
}

```

`+`和`-`符号指示值的符号。 加号可用于表示我们有一个正数。 可以省略它，并且在大多数情况下可以这样做。

`KotlinMinusSignEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val a = 1

    println(-a)
    println(-(-a))
}

```

减号更改值的符号。

## Kotlin 赋值运算符

赋值运算符`=`将值赋给变量。 变量是值的占位符。 在数学中，=运算符具有不同的含义。 在等式中，`=`运算符是一个相等运算符。 等式的左边等于右边的等式。

```kt
val x = 1

```

在这里，我们为`x`变量分配一个数字。

```kt
x = x + 1

```

这个表达式在数学上没有意义，但是在编程中是合法的。 该表达式将`x`变量加 1。 右边等于 2，并且 2 分配给`x`。

```kt
3 = x

```

此代码行导致语法错误。 我们无法为字面值分配值。

## Kotlin 扩展赋值运算子

扩展赋值运算符是由两个运算符组成的速记运算符。 增强的赋值运算符在其他编程语言中也称为复合赋值运算符。

```kt
a = a + 3
a += 3

```

`+=`复合运算符是这些速记运算符之一。 以上两个表达式相等。 将值 3 添加到变量`a`中。

Kotlin 扩展分配运算符为：

```kt
+=  -=   *=   /=   %=   

```

下面的示例使用两个复合运算符。

`KotlinAugmentedAssignmentOperatorsEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    var a = 1
    a = a + 1

    println(a)

    a += 5
    println(a)

    a *= 3
    println(a)
}

```

我们使用`+=`和`*=`复合运算符。

```kt
var a = 1
a = a + 1

```

`a`变量被初始化为 1。 使用非速记符号将值 1 添加到变量。

```kt
a += 5

```

使用`+=`复合运算符，将 5 加到`a`变量中。 该语句等于`a = a + 5`。

```kt
a *= 3

```

使用`*=`运算符，将`a`乘以 3。该语句等于`a = a * 3`。

```kt
2
7
21

```

这是示例输出。

## Kotlin 连接字符串

在 Kotlin 中，`+`运算符还用于连接字符串。

`KotlinConcatenateStringsEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    println("Return " + "of " + "the king.")
    println("Return".plus(" of").plus(" the king."))
}

```

我们将三个字符串连接在一起。

```kt
println("Return " + "of " + "the king.")

```

字符串用`+`运算符连接。

```kt
println("Return".plus(" of").plus(" the king."))

```

连接字符串的另一种方法是`plus()`方法。

## Kotlin 增减运算符

将值递增或递减一个是编程中的常见任务。 Kotlin 为此有两个方便的运算符：`++`和`--`。

```kt
x++
x = x + 1
...
y--
y = y - 1

```

上面两对表达式的作用相同。

`KotlinIncDecEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    var x = 6

    x++
    x++

    println(x)

    x--
    println(x)
}

```

在上面的示例中，我们演示了两个运算符的用法。

```kt
int x = 6

x++
x++

```

将`x`变量初始化为 6。然后将`x`递增两次。 现在变量等于 8。

```kt
x--

```

我们使用减量运算符。 现在变量等于 7。

## Kotlin 算术运算符

下表是 Kotlin 中的算术运算符表。

| 符号 | 名称 |
| --- | --- |
| `+` | 加法 |
| `-` | 减法 |
| `*` | 乘法 |
| `/` | 乘法 |
| `%` | 余数 |

以下示例显示了算术运算。

`KotlinArithmeticOperatorsEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val a = 10
    val b = 11
    val c = 12

    val add = a + b + c
    val sb = c - a
    val mult = a * b
    val div = c / 3
    val rem = c % a

    println(add)
    println(sb)
    println(mult)
    println(div)
    println(rem)
}

```

在前面的示例中，我们使用加法，减法，乘法，除法和余数运算。 这些都是数学所熟悉的。

```kt
val rem = c % a

```

`%`运算符称为余数或模运算符。 它找到一个数除以另一个的余数。 例如`9 % 4`，9 模 4 为 1，因为 4 两次进入 9 且余数为 1。

整数除法和浮点除法之间有区别。

`KotlinDivisionEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val c = 5 / 2
    println(c)

    val d = 5 / 2.0
    println(d)
}

```

在前面的示例中，我们将两个数字相除。

```kt
val c = 5 / 2

```

在这段代码中，我们完成了整数除法。 除法运算的返回值为整数。 当我们将两个整数相除时，结果是一个整数。

```kt
val d = 5 / 2.0

```

如果值之一是`double`或`float`，则执行浮点除法。 在我们的例子中，第二个操作数是双精度数，因此结果是双精度数。

```kt
2
2.5

```

我们看到了程序的结果。

## Kotlin 布尔运算符

在 Kotlin 中，我们有三个逻辑运算符。

| 符号 | 名称 |
| --- | --- |
| `&&` | 逻辑与 |
| <code>&#124;&#124;</code> | 逻辑或 |
| `!` | 否定 |

布尔运算符也称为逻辑运算符。

`KotlinBooleanExpEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val x = 3
    val y = 8

    println(x == y)
    println(y > x)

    if (y > x) {

        println("y is greater than x")
    }
}

```

许多表达式导致布尔值。 例如，在条件语句中使用布尔值。

```kt
println(x == y)
println(y > x)

```

关系运算符始终导致布尔值。 这两行分别显示`false`和`true`。

```kt
if (y > x) {

    println("y is greater than x")
}

```

仅在满足括号内的条件时才执行`if`语句的主体。 `y > x`返回`true`，因此消息`"y`大于`x"`被打印到终端。

`true`和`false`关键字表示 Kotlin 中的布尔字面值。

`KotlinAndOperatorEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val a = true && true
    val b = true && false
    val c = false && true
    val d = false && false

    println(a)
    println(b)
    println(c)
    println(d)
}

```

该代码示例显示了逻辑和（`&&`）运算符。 仅当两个操作数均为`true`时，它的评估结果为`true`。

```kt
true
false
false
false

```

只有一个表达式可得出`true`。

如果两个操作数中的任何一个为`true`，则逻辑或（`||`）运算符的计算结果为`true`。

`KotlinOrOperatorEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val a = true || true
    val b = true || false
    val c = false || true
    val d = false || false

    println(a)
    println(b)
    println(c)
    println(d)
}

```

如果运算符的任一侧为真，则操作的结果为真。

```kt
true
true
true
false

```

四个表达式中的三个表示为`true`。

否定运算符`!`将`true`设为`false`，并将`false`设为`false`。

`KotlinNegationEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    println(! true)
    println(! false)
    println(! (4 < 3))
}

```

该示例显示了否定运算符的作用。

```kt
false
true
true

```

这是程序的输出。

## Kotlin 比较运算符

比较运算符用于比较值。 这些运算符总是产生布尔值。

| 符号 | 含义 |
| --- | --- |
| `<` | 小于 |
| `<=` | 小于或等于 |
| `>` | 大于 |
| `>=` | 大于或等于 |
| `==` | 等于 |
| `!=` | 不等于 |

比较运算符也称为关系运算符。

`KotlinComparisonOperatorsEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    println(3 < 4);
    println(3 == 4);
    println(4 >= 3);
    println(4 != 3);
}

```

在代码示例中，我们有四个表达式。 这些表达式比较整数值。 每个表达式的结果为`true`或`false`。 在 Kotlin 中，我们使用`==`比较数字。 （某些语言（例如 Ada，Visual Basic 或 Pascal）使用`=`比较数字。）

## Kotlin 按位运算符

与 Java 不同，Kotlin 中没有按位运算符。 Kotlin 已经命名了执行按位运算的函数。

*   `shl(bits)` – 有符号左移（Java 的`<<`）
*   `shr(bits)` – 有符号右移（Java 的`>>`）
*   `ushr(bits)` – 无符号右移（Java 的`>>>`）
*   `and(bits)` – 按位与
*   `or(bits)` – 按位或
*   `xor(bits)` – 按位异或
*   `inv()` – 按位反转

这些函数仅适用于`Int`和`Long`类型。

按位操作在两个数字之间进行逐位比较。 仅当操作数中的两个对应位均为 1 时，位位置的结果才为 1。

```kt
      00110
   &  00011
   =  00010

```

第一个数字是二进制符号 6，第二个数字是 3，结果是 2。

```kt
println(6 and 3) // prints 2
println(3 and 6) // prints 2

```

按位或操作在两个数字之间进行逐位比较。 如果操作数中的任何对应位为 1，则位位置的结果为 1。

```kt
     00110
   | 00011
   = 00111

```

结果为`00110`或十进制 7。

```kt
println(6 or 3) // prints 7
println(3 or 6) // prints 7

```

## Kotlin `is`运算符

要在运行时检查对象是否符合给定类型，我们可以使用`is`运算符或其否定形式`!is`。

`KotlinIsOperatorEx.kt`

```kt
package com.zetcode

open class Base
class Derived : Base()

fun main(args: Array<String>) {

    val b = Base()
    val d = Derived()

    println(d is Base)
    println(b is Derived)
    println(d is Any)
}

```

在示例中，我们有两个类：一个基类和一个从基类派生的类。

```kt
println(d is Base)

```

此行检查变量`d`是否指向作为`Base`类实例的类。 由于`Derived`类继承自`Base`类，因此它也是`Base`类的实例。 该行打印正确。

```kt
println(b is Derived)

```

`b`对象不是`Derived`类的实例。 该行显示`false`。

```kt
println(d is Any) 

```

每个类都有`Any`作为超类。 因此，`d`对象也是`Any`类的实例。

```kt
true
false
true

```

这是程序的输出。

## Kotlin Lambda 运算符

Kotlin 具有 lambda 运算符（`->`）。 它分隔了 lambda 表达式的参数和主体。

`KotlinLambdaOperatorEx.kt`

```kt
package com.zetcode

import java.util.Arrays

fun main(args: Array<String>) {

    val words = arrayOf("kind", "massive", "atom", "car", "blue")

    Arrays.sort(words) { s1: String, s2: String -> s1.compareTo(s2) }

    println(Arrays.toString(words))
}

```

在示例中，我们定义了一个字符串数组。 使用`Arrays.sort()`方法和 lambda 表达式对数组进行排序。

```kt
[atom, blue, car, kind, massive]

```

这是输出。

## Kotlin 双冒号运算符

双冒号运算符（：:)用于创建类或函数引用。

`KotlinDoubleColonOperatorEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val c = String::class

    c.supertypes.forEach { e -> println(e) }

    val words = listOf("car", "forest", "Bible")
    println(words.map(String::length))
}

```

在代码示例中，我们使用双冒号运算符创建对类和函数的引用。

```kt
val c = String::class

c.supertypes.forEach { e -> println(e) }

```

对于双冒号运算符，我们指的是`String`类。 我们打印其所有祖先。

```kt
val words = listOf("car", "forest", "Bible")
println(words.map(String::length))

```

在这里，我们将`length()`函数应用于列表的所有单词。

```kt
kotlin.Comparable<kotlin.String>
kotlin.CharSequence
java.io.Serializable
kotlin.Any
[3, 6, 5]

```

这是输出。

## Kotlin 范围运算符

Kotlin 范围运算符（`..`）允许创建值范围。

`KotlinRanageOperatorEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    for (i in 1..14 step 3) {

        println(i)
    }
}

```

该示例使用范围运算符在`for`循环中创建整数序列。

```kt
1
4
7
10
13

```

这是输出。

## 非空断言运算符

非`null`断言运算符（`!!`）会将任何值转换为非`null`类型，并且如果该值为`null`则引发异常。

`KotlinNullAssertionOperatorEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

//    val words = listOf("forest", null, "Bible", "sky")
    val words = listOf("forest", "Bible", "sky")

    var nOfChars: Int = 0

    for (word in words) {

        val n = word!!.length
        nOfChars += n
    }

    println("There are ${nOfChars} characters in the list")
}

```

该示例计算单词列表中的字符数。 如果列表包含空值，则抛出`KotlinNullPointerException`。

## Kotlin Elvis 运算符

Elvis 运算符？：如果不为 null，则返回其第一个表达式，否则返回第二个表达式。

`KotlinElvisOperatorEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val words = listOf("forest", null, "Bible", "sky")

    for (word in words) {

        val n = word?.length ?: 0

        println("${word} has ${n} letters")
    }
}

```

在示例中，我们使用 Elvis 运算符检查列表中的空值。

```kt
val n = word?.length ?: 0

```

如果变量`word`包含 null，则？：返回 0。

```kt
forest has 6 letters
null has 0 letters
Bible has 5 letters
sky has 3 letters

```

这是输出。

## Kotlin 空安全运算符

Kotlin 的`null`安全操作符`?.`提供了安全的方法调用-仅当对象不为`null`时才调用方法。

`KotlinNullSafetyOperatorEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val words = listOf("forest", null, "Bible", "sky")

    for (word in words) {

        println(word?.toUpperCase())
}

```

在示例中，我们将字符串转换为大写； 我们使用`null`安全运算符。 对于`null`值，不调用该方法。

```kt
FOREST
null
BIBLE
SKY

```

这是输出。

## Kotlin 索引访问运算符

Kotlin 索引访问运算符用于从数组获取值。

`KotlinIndexAccessOperatorEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val nums = arrayOf(3, 2, 1, 4, 5, 6, 7)

    val v1 = nums[0]
    val v2 = nums[3]

    println(v1)
    println(v2)
}

```

在示例中，我们使用`[]`运算符从数组中检索两个值。

## Kotlin 引用相等运算符

Kotlin 区分结构相等和引用相等。 结构相等运算符（`==`）检查两个对象是否具有相同的内容。 引用相等运算符（`===`）检查变量是否指向内存中的同一对象。

`KotlinreferentialEqualityOperatorEx.kt`

```kt
package com.zetcode

data class Item(var name: String, var color: String)

fun main(args: Array<String>) {    

    val i1 = Item("coin", "brown")
    val i2 = i1

    println("Output: ${i1 == i2}")
    println("Output: ${i1 === i2}")

    val i3 = Item("coin", "brown")
    val i4 = Item("coin", "brown")

    println("Output: ${i3 == i4}")
    println("Output: ${i3 === i4}")
}

```

该示例演示了`==`和`===`运算符之间的区别。

```kt
Output: true
Output: true
Output: true
Output: false

```

这是输出。

## Kotlin 运算符优先级

运算符优先级告诉我们首先评估哪个运算符。 优先级对于避免表达式中的歧义是必要的。

以下表达式 28 或 40 的结果是什么？

```kt
3 + 5 * 5

```

像数学中一样，乘法运算符的优先级高于加法运算符。 结果是 28。

```kt
(3 + 5) * 5

```

要更改评估的顺序，可以使用括号。 括号内的表达式始终首先被求值。 上面的表达式的结果是 40。

`KotlinOperatorPrecedenceEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    println(3 + 5 * 5)
    println((3 + 5) * 5)

    println(!true or true)
    println(!(true or true))
}

```

在此代码示例中，我们显示一些表达式。 每个表达式的结果取决于优先级。

```kt
println(3 + 5 * 5)

```

该行打印 28。乘法运算符的优先级高于加法。 首先，计算`5 * 5`的乘积，然后加 3。

```kt
println((3 + 5) * 5)

```

可以通过使用方括号来更改表达式的求值。 在这种情况下，将评估`3 + 5`，然后将该值乘以 5。此行显示 40。

```kt
println(!true or true)

```

在这种情况下，求反运算符的优先级高于按位或。 首先，将初始`true`值取反为`false`，然后`|`运算符将`false`和`true`组合在一起，最后给出`true`。

```kt
28
40
true
false

```

这是示例输出。

## 关联规则

有时，优先级不能令人满意地确定表达式的结果。 还有另一个规则称为关联性。 运算符的关联性决定了具有相同优先级的运算符的评估顺序。

```kt
9 / 3 * 3

```

此表达式的结果是 9 还是 1？ 乘法，删除和模运算符从左到右关联。 因此，该表达式的计算方式为：`(9 / 3) * 3`，结果为 9。

算术运算符，布尔运算符和关系运算符从左到右关联。 三元运算符，递增，递减，一元正负，取反，按位不，类型强制转换，对象创建运算符从右到左关联。

`KotlinAssociativityRuleEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    var j = 0

    j *= 3 + 1

    println(j)
}

```

在示例中，我们的关联规则确定表达式的结果。

```kt
var j = 0

j *= 3 + 1

```

增强的赋值运算符从右到左关联。 我们可能期望结果为 1。但是实际结果为 0。由于有关联性。 首先评估右边的表达式，然后应用复合赋值运算符。

## 计算素数

在下面的示例中，我们将计算素数。

`KotlinPrimeNumbersEx.kt`

```kt
package com.zetcode

fun main(args: Array<String>) {

    val nums = intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
            14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28)

    print("Prime numbers: ")

    for (num in nums) {

        if (num == 0 || num == 1) {
            continue
        }

        if (num == 2 || num == 3) {

            print(num.toString() + " ")
            continue
        }

        var i = Math.sqrt(num.toDouble()).toInt()

        var isPrime = true

        while (i > 1) {

            if (num % i == 0) {

                isPrime = false
            }

            i--
        }

        if (isPrime) {

            print(num.toString() + " ")
        }
    }

    print('\n')
}

```

在上面的示例中，我们处理了几个运算符。 质数（或质数）是一个自然数，它具有两个截然不同的自然数除数：1 和它本身。 我们选择一个数字并将其除以 1 到所选数字的数字。 实际上，我们不必尝试所有较小的数字。 我们可以将数字除以所选数字的平方根。 该公式将起作用。 我们使用余数除法运算符。

```kt
val nums = intArrayOf(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
        14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28)

```

我们将从这些数字计算素数。

```kt
if (num == 0 || num == 1) {
    continue
}

```

值 0 和 1 不被视为素数。

```kt
if (num == 2 || num == 3) {

    print(num.toString() + " ")
    continue
}

```

我们跳过 2 和 3 的计算。它们是质数。 请注意等式和条件或运算符的用法。 `==`的优先级高于`||`运算符。 因此，我们不需要使用括号。

```kt
var i = Math.sqrt(num.toDouble()).toInt()

```

如果我们仅尝试小于所讨论数字的平方根的数字，那么我们可以。

```kt
while (i > 1) { 
    ...
    i--;
}

```

这是一个`while`循环。 `i`是计算出的数字的平方根。 我们使用减量运算符将每个循环周期的`i`减 1。 当`i`小于 1 时，我们终止循环。 例如，我们有 9。9 的平方根是 3。我们将 9 的数字除以 3 和 2。这对于我们的计算就足够了。

```kt
if (num % i == 0) {

    isPrime = false
}

```

如果余数除法运算符针对任何`i`值返回 0，则说明该数字不是质数。

在本教程中，我们介绍了 Kotlin 运算符。 您可能也对相关教程感兴趣： [Kotlin 列表教程](/kotlin/lists/)， [Kotlin 变量教程](/kotlin/variables/)， [Kotlin 字符串教程](/kotlin/strings/)， [Kotlin 控制流教程](/kotlin/controlflow/) 和 [Kotlin 数组教程](/kotlin/arrays/)。