Kotlin

Kotlin是一種在Java虛擬機上執行的靜態型別程式語言,它也可以被編譯成為JavaScript原始碼。它主要是由俄羅斯聖彼得堡JetBrains開發團隊所發展出來的程式語言,其名稱來自於聖彼得堡附近的科特林島[3]2012年1月,著名期刊《Dr. Dobb's Journal》中Kotlin被认定为該月的最佳語言。[4]雖然与Java語法並不相容,但在JVM環境中Kotlin被設計成可以和Java程式碼相互運作,並可以重複使用如Java集合框架等的現有Java引用的函数库。Hathibelagal写道,“如果你正在为Android开发寻找一种替代编程语言,那么应该试下Kotlin。它很容易在Android项目中替代Java或者同Java一起使用。”

Kotlin
設計者JetBrains
實作者JetBrains與開源貢獻者
2011
穩定版本
Kotlin 1.3.72
(2020年4月15日2020-04-15 [1]
預覽版本
Kotlin 1.4-M1
(2020年3月23日2020-03-23 [2]
型態系統靜態類型类型推论
系统平台輸出Java虛擬機Java字节码以及JavaScript原始碼
作業系統任何支援JVM或是JavaScript的直譯器
許可證Apache 2
文件扩展名.kt .kts
網站kotlinlang.org
啟發語言
JavaScalaGroovyC#Gosu

历史

2011年7月,JetBrains推出Kotlin项目,这是一个面向JVM的新语言,它已被开发一年之久。[5]JetBrains负责人Dmitry Jemerov说,大多数语言没有他们正在寻找的特性,但是Scala除外。但是,他指出Scala的编译时间過慢这一明显缺陷。[5]Kotlin的既定目标之一是像Java一样快速编译。2012年2月,JetBrains以Apache 2许可证开源此项目。[6]

Jetbrains希望这个新语言能够推动IntelliJ IDEA的销售。[7]

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

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

语法

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,即(固定的)值)關鍵字定義唯讀变量,定義後其值無法修改[10]

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

使用var(全稱為variable,即變量)關鍵字定義可變變量。

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

函数

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

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

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

程序的入口点

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

// 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。

package MyStringExtensions

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

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

利用函数扩展,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):

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

函数嵌套

Kotlin支持函数嵌套(nested functions),允許函數内再定义函數,類似JavaScript、C#与Python语言。

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.isEmpty()) {
               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 包含解構式可分離其元素:

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

抽象類別

抽象類別(Abstract classes)定義抽象或純虚擬(Pure Virtual)占位函数,需要被继承。抽象類別預設是open的。

// 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)聲明,用于控制類別与成员在继承时的可见性(作用域)。它们可用於類別及其成員:

public
internal
protected
private

用于類別的成员声明时,含义如下:

  • public:全局可见。此为默认的类型。
  • internal:在当前模块中可见。
  • protected:在当前類別的一级子類別中可见,如果子類別再被继承,则在下一级子類別中不可见。
  • private:在当前類別中可见。

用于顶层声明时,含义如下:

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

例如:

// 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关键字可以省略。如果构造函数中没有其它操作,大括号也可以省略。

// 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。

// 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 應用程式,[11]現已棄用。[12]

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。

$ 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),即成為可執行檔。

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

為了執行Kotlin 脚本,我們在运行编譯器時再加上-script選項。

$ kotlinc -script list_folders.kts "path_to_folder_to_inspect"

Kotlin 的 hello world 例子

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):
fun sayHello(maybe: String?, neverNull: Int) {
   // use of elvis operator
   val name: String = maybe ?: "stranger"
   println("Hello $name")
}

使用安全導引(safe navigation)运算符:

// 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。[13]

// 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 夾帶參數,他們可定义在大括弧内,並以->运算符區隔。

// 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") }

参考资料

  1. https://github.com/JetBrains/kotlin/releases/latest
  2. https://github.com/JetBrains/kotlin/tree/v1.4-M1
  3. Heiss, Janice. . oracle.com. Oracle Technology Network. April 2013 [February 2, 2014]. (原始内容存档于2017-05-08).
  4. Breslav, Andrey. . drdobbs.com. January 20, 2012 [February 2, 2014]. (原始内容存档于2015-10-22).
  5. Krill, Paul. . infoworld.com. InfoWorld. Jul 22, 2011 [February 2, 2014]. (原始内容存档于2014-07-15).
  6. Waters, John. . ADTmag.com/. 1105 Enterprise Computing Group. February 22, 2012 [February 2, 2014]. (原始内容存档于2016-03-29).
  7. . [2017-05-18]. (原始内容存档于2014-04-21). we expect Kotlin to drive the sales of IntelliJ IDEA
  8. . Blog.jetbrains.com. 2016-02-15 [2017-04-11]. (原始内容存档于2016-10-22).
  9. Shafirov, Maxim. . May 17, 2017 [2017-05-18]. (原始内容存档于2021-01-31). Today, at the Google I/O keynote, the Android team announced first-class support for Kotlin.
  10. . Kotlin. Jetbrains. [19 January 2018]. (原始内容存档于2021-01-29).
  11. . [2018-06-02]. (原始内容存档于2020-12-13).
  12. anko/GOODBYE.md
  13. . Kotlin. Jetbrains. [19 January 2018]. (原始内容存档于2021-01-22).

外部連結

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.