Hello Kotlin

Hello Kotlin

很多人都喜欢从经典的 Hello world 程序开始介绍一门语言。这里我也贴上一个 Kotlin 的 Hello world 程序,虽然同样是运行在 JVM 上的程序,但是看起来与 Java 还是有很大的不同的。

1
2
3
4
5
// helloworld.kt
val name = "Kotlin"
fun main(args: Array<String>) {
println("hello, $name")
}

下面拆解一下上面的代码,看看 Kotlin 中新奇的地方。后面会整理 Kotlin 基本的语法知识,主要关注与 Java 有差别的地方,太基本的就不多说了。

拆解说明

  1. 顶层函数/变量:在 Kotlin 中函数和变量的声明可以直接在文件中,不需要像 Java 一样要用额外类来包裹入口。
  2. 函数定义:Kotlin 的函数声明采用 fun 关键字,后面加上函数名字和参数列表,最后才是返回值。
  3. 函数变量:函数的变量是名称在前,类型在后的。
  4. 输出语句:Kotlin 标准库封装了若干方法,可以不导入直接使用,println 就是其一。
  5. 字符串模板:Kotlin 支持直接在字符串中引用变量,最终的结果将是变量拼接后的结果。

变量

val 和 var

在 Kotlin 中有两种形式的变量声明的。

  • 不可变的 val。val 声明的变量不能在初次赋值后再次赋值,类似 Java 中的 final 声明的变量。
  • 可变的 var。与 val 相反,可以反复赋值。

这些关键字在现代的编程语言中很常见,但是他们的含义可能不一样。 Javascript 中的 var 是可以反复赋值,并且可以赋值不同的类型的变量的。但是在 Kotlin 中,var 的变量类型不能变更。

类型推导

Kotlin 变量的声明时可以不用指定,编译器会自动推导类型。如果无法推导类型则必须显式地指定类型。

1
2
val PI = 3.141592653
var lang_name = "kotlin"

上面两个声明变量的语句并没有指定类型,因为赋值初始化的值可以推倒出该变量的类型。如果想指定类型的话可以这样:

1
2
val PI: Double = 3.141592653
var lang_name: String = "kotlin"

在 Kotlin 中不能使用 Java 中 int, double, boolean 等内置变量,而应该使用对应的包装类。比如 int 对应的 Int,double 对应的 Double 等。

函数

Kotlin 函数声明方式与 Java 中已经大为不同,上面例子的 main 函数是个无返回函数,可以省略返回类型,如果要指定类型可以使用 Unit 指定(例如用在声明无返回的函数类型变量上)。

1
2
3
fun log(msg: String): Unit {
println("[Kotlin] $msg")
}

简化函数

如果函数主体只有一条语句,则可以简化函数的写法,以下 log 函数的返回值将自动推导成 println 的返回值。

1
fun log(msg: String) = println("[Kotlin] $msg")

Kotlin 的函数后面单独仔细总结一下,此处不再多说。

分支

Kotlin 增加了一些强大的分支控制语法,甚至可以自己自定义语法,重载操作符。

when 表达式

when 表达式类似 switch,可以根据提供的值选择要执行代码。不同的是 when 是一个表达式有返回值,而且 when 比 switch 要强大太多。

1
2
3
4
5
when (font) {
Font.YH -> "雅黑"
Font.PF -> "苹方"
else -> "其他"
}

以上例子中的 else 的作用和 switch 中的 default 类似。when 表达式中没有要求在每个分支里写 break,因为只有对应匹配的分支会执行。如果想匹配多个条件可以用逗号分隔开。

1
2
3
4
5
6
when (font) {
Font.YH -> "雅黑"
Font.PF -> "苹方"
Font.HT, Font.HT_SC -> "黑体"
else -> "其他"
}

与 Java 中的 switch 不同的是,when 可以对所有对象使用。同时,when 的参数也是可以省略的。当 when 的参数被省略的时候,将会执行分支条件为真的分支,如果都不符合则执行 else 分支。

1
2
3
4
5
6
fun fontName(font: String): String {
when {
Font.YH == font -> "雅黑"
else -> "其他"
}
}

前面提到,when 是表达式,那可以用在表达式可以用的任何地方,比如表达式为主体的函数。

1
2
3
4
5
6
fun fontName(font: String) = when (font) {
Font.YH -> "雅黑"
Font.PF -> "苹方"
Font.HT, Font.HT_SC -> "黑体"
else -> "其他"
}

if 表达式

if 在 Kotlin 中也是一个表达式,也可以赋值给一个变量或者作为表达式主体。if 和 when 等都有一个特性,就是智能类型转换。

1
2
3
if (a is Num) {
a += 6
}

代码中 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
2
3
for (i in 1..5) {
println(i)
}

如果想倒数数字的话需要使用 downTo 来表示。

1
2
3
for (i in 5 downTo 1) {
println(i)
}

downTo 还可以与 step 一起用,设置每次数据枚举的步数。

1
2
3
for (i in 5 downTo 1 step 2) {
println(i)
}

与其类似的还有 until,用于配置不右包含的范围,比如要取 1 到 size - 1 的范围可以这么设置

1
2
3
for (i in 1 until l.size ) {
println(i)
}

实际上,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 所有特性。

作者

Jakes Lee

发布于

2017-05-24

更新于

2021-11-18

许可协议

评论