Kotlin

Kotlin是一种在Java虚拟机上执行的静态型别程式语言，它也可以被编译成为JavaScript源代码。

## 历史

2011年7月，JetBrains在俄罗斯圣彼得堡的开发团队推出Kotlin项目，其名称来自于圣彼得堡附近的科特林岛。2012年1月，著名期刊《Dr. Dobb's Journal》中Kotlin被认定为该月的最佳语言。这是一个面向JVM的新语言，它已被开发一年之久。JetBrains负责人Dmitry Jemerov说，大多数语言没有他们正在寻找的特性，但是Scala除外。但是，他指出Scala的编译时间过长这一明显缺陷。Kotlin的既定目标之一是像Java一样快速编译。2012年2月，JetBrains以Apache 2许可证开源此项目。

JetBrains希望这个新语言能够推动IntelliJ IDEA的销售。

虽然与Java语法并不相容，但在JVM环境中Kotlin被设计成可以和Java程式码相互运作，并可以重复使用如Java集合框架等的现有Java引用的函数库。Hathibelagal写道，“如果你正在为Android开发寻找一种替代编程语言，那么应该试下Kotlin。它很容易在Android项目中替代Java或者同Java一起使用。”

Kotlin v1.0于2016年2月15日发布。这被认为是第一个官方稳定版本，并且JetBrains已准备从该版本开始的长期向后兼容性。

在Google I/O 2017中，Google宣布在Android上为Kotlin提供最佳支持。

## 语法

Kotlin很明显受到Java、C#、JavaScript、Scala、Groovy等语言的影响。例如Kotlin可以直接通过`println("Hello, ${name}")`或`println("Hello, $name")`来使用字串模板，和古老的shell script类似。又如Kotlin中的分号是可选的，这类似JavaScript，而且Groovy、Scala也有同样的能力。Kotlin常量定义关键字是`val`（不同于变量定义关键字`var`），表示固定值，这功能来自Scala，Swift也有类似功能。

需要注意，Kotlin没有关键字`new`。

### 变量

使用`val`（全称为value，即（固定的）值）关键字定义只读变量，定义后其值无法修改

```Kotlin
val a: Int = 1 // 定義a為`Int`類型的唯讀變量，其值為1
val b = 2 // 自動檢測b為`Int`類型
```

使用`var`（全称为variable，即变量）关键字定义可变变量。

```Kotlin
var x = 5 // App 定義一個`Int`，值為5
x = 1 // 修改值為1
```

### 函数

使用`fun`关键字定义一个函数。

```Kotlin
fun sum(a: Int, b: Int): Int {
    return a + b
}
```

上例定义了一个传入两个Int变量，并返回两数之和的求和函数。

### 程序的入口点

类似于 C、 C++、 C#、 Java 和 Go， Kotlin 程序的入口点是一个名为“main”的函数。main 函数有一个包含命令行选项的参数（从 Kotlin 1.3 开始是可选的）。Kotlin 支持像 Perl 和 Unix shell 那样的字符串模板。类型推断也是支持的。

```kotlin
// Hello, world! 範例
fun main() {
    val scope = "World"
    println("Hello, $scope!")
}

fun main(args: Array<String>) {
    for (arg in args) {
        println(arg)
    }
}
```

### 函数扩展

Kotlin与C#、JavaScript类似，能够扩展类别的新功能，而无需继承该类别，或使用像装饰器（decorator）这样的任何类型的设计模式（design pattern）。扩展函数可以称为Kotlin的核心，在标准库里到处充斥着扩展函数。

扩展函数是静态分发的，也就是说，它们不是以接收者类型为准的虚拟函数。这意味着调用的扩展函数是由函数调用所在的表达式的类型来决定的，而不是由表达式运行时求值结果决定的。

在下述例子中，String类别被扩展出一个成员lastChar。

```kotlin
package MyStringExtensions

fun String.lastChar(): Char = get(length - 1)

>>> println("Kotlin".lastChar()) 
```

利用函数扩展，Kotlin也支持运算符重载：

```kotlin
// overloading '+' operator using an extension method
operator fun Point.plus(other: Point): Point {
    return Point(x + other.x, y + other.y)
}

>>> val p1 = Point(10, 20)
>>> val p2 = Point(30, 40)
>>> println(p1 + p2)
Point(x=40, y=60)
```

### getter和setter

Kotlin像C#一样支持属性（property）。

### 解包引数

类似Python, 解包（unpack）指的是对实际参数的解包，只需在前面加一个星号* 即可，如test（*a）:

```kotlin
fun main(args: Array<String>) { 
    val list = listOf("args: ", *args)
    println(list)
}
```

### 函数嵌套

Kotlin支持函数嵌套（nested functions），允许函数内再定义函数，类似JavaScript、C#与Python语言。

```kotlin
class User(
    val id:      Int, 
    val name:    String, 
    val address: String) { 

    fun saveUser(user: User) {
       fun validate(user: User, value: String, fieldName: String) {
           if (value.isBlank()) {
               throw IllegalArgumentException(
                  "Can't save user ${user.id}: empty $fieldName")
           }
       }

       validate(user, user.name, "Name") 
       validate(user, user.address, "Address")
       // Save user to the database
    }
}
```

### 解构声明

Kotlin支持解构声明，这与Python的迭代解包相似。

例如, collection object 包含解构式可分离其元素:

```kotlin
for ((index, element) in collection.withIndex()) { 
     println("$index: $element")
}
```

### 抽象类别

抽象类别（Abstract classes）定义抽象或纯虚拟（Pure Virtual）占位函数，需要被继承。抽象类别预设是open的。

```kotlin
// No need for the open keyword here, its already open by default
abstract class Animated {

    // This virtual function is already open by default as well
    abstract fun animate()

    open fun stopAnimating() { }

    fun animateTwice() { }
}
```

### 类别属性

Kotlin 提供下列的关键字来限制顶层（top-level）声明，用于控制类别与成员在继承时的可见性（作用域）。它们可用于类别及其成员:

```kotlin
public
internal
protected
private
```

用于类别的成员声明时，含义如下：

- public：全局可见。此为默认的类型。
- internal：在当前模块中可见。
- protected：在当前类别的一级子类别中可见，如果子类别再被继承，则在下一级子类别中不可见。
- private：在当前类别中可见。

用于顶层声明时，含义如下：

- public：全局可见。此为默认的类型。
- internal：在当前模块中可见。
- private：在当前文件中可见。

例如:

```kotlin
// Class is visible only to current module
internal open class TalkativeButton : Focusable {
    // method is only visible to current class 
    private   fun yell() = println("Hey!") 

    // method is visible to current class and derived classes
    protected fun whisper() = println("Let's talk!")
}
```

### 主构造函数 vs. 二级构造函数

在Kotlin 中类别可以有一个主构造函数以及多个二级构造函数。如果主构造函数没有注解或可见性说明，则`constructor`关键字可以省略。如果构造函数中没有其它操作，大括号也可以省略。

```kotlin
// Example of class using primary constructor syntax
// (Only one constructor required for this class)
class User(
    val nickname: String, 
    val isSubscribed: Boolean = true) {
    ...
}
```

Kotlin 的二级构造函数更类似于 C++, C#, 和 Java。

```kotlin
// Example of class using secondary constructor syntax
// (more than one constructor required for this class)
class MyButton : View {

    // Constructor #1 
    constructor(ctx: Context) : super(ctx) { 
        // ... 
    } 

    // Constructor #2
    constructor(ctx: Context, attr: AttributeSet) : super(ctx, attr) { 
        // ... 
    }
}
```

### Anko library

Anko 是一组为Kotlin 打造的函数库，其功能是用来开发Android UI 应用程序，随着同类功能的Jetpack Compose发展，Anko现已弃用。

```kotlin
fun Activity.showAreYouSureAlert(process: () -> Unit) {
    alert(
      title   = "Are you sure?",
      message = "Are you really sure?") 
    {
      positiveButton("Yes") { process() }
      negativeButton("No") { cancel() }
    }
}
```

### Kotlin 交互模式

Kotlin除了编译成Java字节码运行，也可以作为脚本语言解释运行，此特性使得Kotlin可以以交互模式运行。交互模式是脚本语言具有的特性，解释器可以立即运行用户输入的代码，并反馈运行结果。典型的语言有Python、JavaScript（在V8引擎支持下）、Ruby。

```bash
$ kotlinc-jvm
type :help for help; :quit for quit
>>> 2+2
4
>>> println("Welcome to the Kotlin Shell")
Welcome to the Kotlin Shell
>>>
```

### Kotlin 也是脚本语言

Kotlin 亦可视为脚本语言（scripting language）。其脚本存成 Kotlin source file (.kts)，即成为可执行档。

```kotlin
// list_folders.kts
import java.io.File
val folders = File(args[0]).listFiles { file -> file.isDirectory() }
folders?.forEach { folder -> println(folder) }
```

为了执行Kotlin 脚本，我们在运行编译器时再加上-script选项。

```bash
$ kotlinc -script list_folders.kts "path_to_folder_to_inspect"
```

### Kotlin 的 hello world 例子

```kotlin
fun main(args: Array<String>) {
    
    greet {
        to.place
    }.print()
}

//inline higher-order functions
inline fun greet(s: () -> String) : String = greeting andAnother s()  

//infix functions, extensions, type inference, nullable types, lambda expressions, labeled this, elvis operator
infix fun String.andAnother(other : Any?) = buildString() { append(this@andAnother); append(" "); append(other ?: "") } 

//immutable types, delegated properties, lazy initialization, string templates
val greeting by lazy { val doubleEl: String = "ll"; "he${doubleEl}o" }

//sealed classes, companion objects
sealed class to { companion object { val place = "world"} }

//extensions, Unit
fun String.print() = println(this)
```

### 空变量及其运算

Kotlin对可以为空（nullable）的变量和不可以为空（non-nullable）的变量作了区分。所有的可空对象（nullable objects）必须在定义时加上 "?" 后置于类型之后。开发人员遇到nullable objects时要先确认: null-check 须被执行过，才能赋值。可空性是Kotlin类型系统中帮助开发者避免以往Java的NullPointerException错误的特性。

Kotlin 提供空安全（null-safe）运算符给开发人员:

- (Safe navigation operator) 可用于安全存取（safely access）可能是空对象的函数或属性。如果 object 为空（null）, 该方法将不被调用，而且表达式的值一定为空（null）。
- (Null coalescing operator) 通常称为艾维斯运算符（Elvis operator）:

```kotlin
fun sayHello(maybe: String?, neverNull: Int) {
   // use of elvis operator
   val name: String = maybe ?: "stranger"
   println("Hello $name")
}
```

使用安全导引（safe navigation）运算符:

```kotlin
// returns null if...
// - foo() returns null,
// - or if foo() is non-null, but bar() returns null,
// - or if foo() and bar() are non-null, but baz() returns null.
// vice versa, return value is non-null if and only if foo(), bar() and baz() are non-null
foo()?.bar()?.baz()
```

### 高阶函数与lambda

Kotlin 亦支持高阶函数和lambdas功能。lambda是一种匿名函数，允许开发者直接将表达式定义为函数，这类似于Python。

```kotlin
// the following function takes a lambda, f, and executes f passing it the string, "lambda"
// note that (s: String) -> Unit indicates a lambda with a String parameter and Unit return type
fun executeLambda(f: (s: String) -> Unit) {
    f("lambda")
}
```

Lambdas 可用大括弧来定义。如果lambda 夹带参数，他们可定义在大括弧内，并以运算符区隔。

```kotlin
// the following statement defines a lambda that takes a single parameter and passes it to the println function
val l = { c : Any? -> println(c) }
// lambdas with no parameters may simply be defined using { }
val l2 = { print("no parameters") }
```

## 基本资料

- 文件扩展名：.kt .kts
- 编程范型：多范型：面向对象、函数式、指令式、宣告式、泛型、反射式、并发
- 发行日期：2011
- 设计者：JetBrains
- 开发者：JetBrains与开源贡献者
- 类型系统：静态类型、类型推论
- 受影响于：Java、Scala、Groovy、C#、Gosu
- 平台：输出Java虚拟机、Java字节码以及JavaScript源代码
- 操作系统：任何支援JVM或是JavaScript的直译器
- 许可证：Apache 2