Hello Kotlin
很多人都喜欢从经典的 Hello world 程序开始介绍一门语言。这里我也贴上一个 Kotlin 的 Hello world 程序,虽然同样是运行在 JVM 上的程序,但是看起来与 Java 还是有很大的不同的。
1 | // helloworld.kt |
下面拆解一下上面的代码,看看 Kotlin 中新奇的地方。后面会整理 Kotlin 基本的语法知识,主要关注与 Java 有差别的地方,太基本的就不多说了。
拆解说明
- 顶层函数/变量:在 Kotlin 中函数和变量的声明可以直接在文件中,不需要像 Java 一样要用额外类来包裹入口。
- 函数定义:Kotlin 的函数声明采用 fun 关键字,后面加上函数名字和参数列表,最后才是返回值。
- 函数变量:函数的变量是名称在前,类型在后的。
- 输出语句:Kotlin 标准库封装了若干方法,可以不导入直接使用,println 就是其一。
- 字符串模板:Kotlin 支持直接在字符串中引用变量,最终的结果将是变量拼接后的结果。
变量
val 和 var
在 Kotlin 中有两种形式的变量声明的。
- 不可变的 val。val 声明的变量不能在初次赋值后再次赋值,类似 Java 中的 final 声明的变量。
- 可变的 var。与 val 相反,可以反复赋值。
这些关键字在现代的编程语言中很常见,但是他们的含义可能不一样。 Javascript 中的 var 是可以反复赋值,并且可以赋值不同的类型的变量的。但是在 Kotlin 中,var 的变量类型不能变更。
类型推导
Kotlin 变量的声明时可以不用指定,编译器会自动推导类型。如果无法推导类型则必须显式地指定类型。
1 | val PI = 3.141592653 |
上面两个声明变量的语句并没有指定类型,因为赋值初始化的值可以推倒出该变量的类型。如果想指定类型的话可以这样:
1 | val PI: Double = 3.141592653 |
在 Kotlin 中不能使用 Java 中 int, double, boolean 等内置变量,而应该使用对应的包装类。比如 int 对应的 Int,double 对应的 Double 等。
函数
Kotlin 函数声明方式与 Java 中已经大为不同,上面例子的 main 函数是个无返回函数,可以省略返回类型,如果要指定类型可以使用 Unit 指定(例如用在声明无返回的函数类型变量上)。
1 | fun log(msg: String): Unit { |
简化函数
如果函数主体只有一条语句,则可以简化函数的写法,以下 log 函数的返回值将自动推导成 println 的返回值。
1 | fun log(msg: String) = println("[Kotlin] $msg") |
Kotlin 的函数后面单独仔细总结一下,此处不再多说。
分支
Kotlin 增加了一些强大的分支控制语法,甚至可以自己自定义语法,重载操作符。
when 表达式
when 表达式类似 switch,可以根据提供的值选择要执行代码。不同的是 when 是一个表达式有返回值,而且 when 比 switch 要强大太多。
1 | when (font) { |
以上例子中的 else 的作用和 switch 中的 default 类似。when 表达式中没有要求在每个分支里写 break,因为只有对应匹配的分支会执行。如果想匹配多个条件可以用逗号分隔开。
1 | when (font) { |
与 Java 中的 switch 不同的是,when 可以对所有对象使用。同时,when 的参数也是可以省略的。当 when 的参数被省略的时候,将会执行分支条件为真的分支,如果都不符合则执行 else 分支。
1 | fun fontName(font: String): String { |
前面提到,when 是表达式,那可以用在表达式可以用的任何地方,比如表达式为主体的函数。
1 | fun fontName(font: String) = when (font) { |
if 表达式
if 在 Kotlin 中也是一个表达式,也可以赋值给一个变量或者作为表达式主体。if 和 when 等都有一个特性,就是智能类型转换。
1 | if (a is Num) { |
代码中 if 语句块里的 a 被自动转换为 Num 类型,不需要额外的代码进行手动转换。当然如果想手动进行类型转换可以使用 as 关键字,如下代码得到的 b 的类型即为 Num。
1 | val b = a as Num |
while 和 for
Kotlin 的 while 和 do-while 语法和 Java 的没什么不同。Kotlin 引入了 ranges 的语法,类似 Ruby 的 Range 语法,可以快速枚举制定范围的数据列表,同时枚举范围是闭合的。例如,1..5 表示的是数字 [1,2,3,4,5] 的集合。
1 | for (i in 1..5) { |
如果想倒数数字的话需要使用 downTo 来表示。
1 | for (i in 5 downTo 1) { |
downTo 还可以与 step 一起用,设置每次数据枚举的步数。
1 | for (i in 5 downTo 1 step 2) { |
与其类似的还有 until,用于配置不右包含的范围,比如要取 1 到 size - 1 的范围可以这么设置
1 | for (i in 1 until l.size ) { |
实际上,downTo、step 和 until 都是函数,是由 Kotlin 标准库使用插入函数(infix function)的方式从 Int 中扩展出来的。我们也可以使用类似的方式实现类似的功能,后面再整理 infix 的内容,有兴趣可以参看 Kotlin 标准库中 _Ranges.kt 的源码。Kotlin 标准库含有大量类似的扩展增强方法,很有研究价值。
操作符
在最后,我想单独讲一下 Kotlin 的操作符。Kotlin 的操作除了 Java 原来那套外,还增加了 in、as 和 is 操作符。
- in 表示内容包含。可以用在 if 中判断是否存在集合中,for 中进行遍历。!in 是 not in 的意思,与 in 的作用相反。
- as 用于转换变量类型
- is 用于判断类型
总结
Kotlin 带来了很多新的语法特性,包含有函数式编程的特性又有 Java 的部分内容,难怪别人会说是 JVM 版的 Swift。以上只是简单介绍了 Kotlin 的部分语法特性,还有很多内容没有涉及到。函数相关的内容诸如 infix、lambda 和函数式编程的支持等高级特性并未提及,后面会逐个涉及 Kotlin 所有特性。