Kotlin介绍系列(二)基本语法

方法定义

强类型的语言所以参数和返回值必须定义类型

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

像上例中,如果函数体只有一个表达式,而且能推断出返回类型时,可以写成这样:

1
fun sum(a: Int, b: Int) = a + b

如果无返回类型,那么返回类型可以写

1
2
3
4
5
#### 声明变量
只读变量,相当于Java中用final修饰的,使用val声明
``` Kotlin
val a: Int = 1
val b = 2 // 这里省略类型是因为此时类型是可以推断出来的

可变变量,使用关键字var声明

1
2
var c = 5 // 类型同样可推断
c += 5

字符串模板

Kotlin中有类似JavaScript的字符串模板

1
2
3
4
var c = 5
val s1 = "a is $c" // now, s1 = "a is 5"
val s2 = "abc"
val s3 = "$s2.length is ${s2.length}" // now, s3 = "abc.length is 3"

空安全

空安全从来都是一件让人头疼的事情,在Java里,你总是会由于没有做空安全保护说不定哪里就会报类似NullPointerException。

  • 可空变量的声明
    首先,下面这种做法是不行的
    1
    2
    3
    // eg1
    var a: String = "abc"
    a = null // compilation error

因为限定了a的类型是String,那么它就不可以持有null对象
怎么纠正?

1
2
3
// eg2
var b: String? = "abc"
b = null // OK

  • 可空变量的访问
    首先如果我们访问eg1中的a,比如
    l
    1
    2
    3
    4
    这是没问题的,为什么呢,因为a被限定死是String类型,而且也只能被赋予String类型的值,那么,无论如何它不为空,一定有length成员
    那么如果我们访问eg2中的b呢
    ``` Kotlin
    val l = b.length // error: variable 'b' can be null

这时候,我们就需要做空保护了,传统地,我们可以像Java中做空保护一样这样写

1
2
3
4
5
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}

或者用Kotlin的判断语句表达式

1
val l = if (b != null) b.length else -1

还有一种最便利的安全操作符?.
比如

l
1
2
3
这种最方便于链式调用,比如
```Kotlin
bob?.department?.name?.head

过程中有任意一项为空,表达式都会返回null

is(反义是!is)与自动类型转换

is操作符是用来判断一个对象是否是一个类型的实例

1
2
3
4
5
6
7
8
fun getStringLength(obj: Any): Int? {
if (obj is String) {
// `obj` is automatically cast to `String` in this branch
return obj.length
}
// `obj` is still of type `Any` outside of the type-checked branch
return null
}

从上面的例子可以看出,经过is进行类型检查以后,就没有必要进行类型转换了,对象会自动转换成被检查的类型。

when——一个更优秀的switch替代品

when结构里的判断项相当的灵活,可以是一个常量,也可以是表达式(函数,类型检查,范围等)。举例说明:

1
2
3
4
5
when (x) {
0, 1 -> print("x == 0 or x == 1")
2 -> print("x ==2")
else -> print("otherwise")
}

1
2
3
4
5
6
when (x) {
in 1..10 -> print("x is in the range")
in validNumbers -> print("x is valid")
!in 10..20 -> print("x is outside the range")
else -> print("none of the above")
}
1
2
3
4
fun hasPrefix(x: Any) = when(x) {
is String -> x.startsWith("prefix")
else -> false
}

when还可以用作多重if/else选择的替代:

1
2
3
4
5
when {
x.isOdd() -> print("x is odd")
x.isEven() -> print("x is even")
else -> print("x is funny")
}

as强制类型转换

首先声明强制类型转换是非安全的,可能抛出异常。
e.g.:

1
val x: String = y as String

注意如果y可以为null,而null是不可以转换成String的,就会抛出异常。
怎么改正呢?

1
val x: String? = y as String?

前后都可以为空对象。

in 范围判断

先介绍一下在kotlin中可以这样表示范围如

1
2
3
4
5
6
7
8
9
10
11
12
13
配合in操作符就可以理解其表示的含义
e.g..:
```Kotlin
if (i in 1..10) { // equivalent of 1 <= i && i <= 10
println(i)
}
for (i in 1..4) print(i) // prints "1234"
for (i in 4..1) print(i) // prints nothing
for (i in 4 downTo 1) print(i) // prints "4321"
for (i in 1..4 step 2) print(i) // prints "13"
for (i in 1 until 10) { // i in [1, 10), 10 is excluded 不包括10,注意⚠️
println(i)
}

Collections集合与循环/判断

  • 迭代器与集合
    和其他语言类似:

    1
    2
    3
    for (item in items) {
    println(item)
    }
  • 判断元素与集合的关系

    1
    2
    3
    4
    when {
    "orange" in items -> println("juicy")
    "apple" in items -> println("apple is fine too")
    }

可见性修饰

Kotlin有四种可见性修饰符:private, protected, internal, public
用法见下面表格:

修饰符 顶级(声明在package底下) 类级(声明在一个类里)
private 当前文件可见 只当前类可见
protected (不可直接在包下使用此声明) 当前类及其子类可见
internal 当前module可见 当前module可见
public 随处可见 随处可见

值得注意的是,如果不做修饰,默认则是public

例子:

  • 顶级

    1
    2
    3
    4
    5
    6
    // file name: example.kt
    package foo
    private fun foo() {} // visible inside example.kt
    public var bar: Int = 5 // property is visible everywhere
    private set // setter is visible only in example.kt
    internal val baz = 6 // visible inside the same module
  • 类级

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    open class Outer {
    private val a = 1
    protected open val b = 2
    internal val c = 3
    val d = 4 // public by default
    protected class Nested {
    public val e: Int = 5
    }
    }
    class Subclass : Outer() {
    // a is not visible
    // b, c and d are visible
    // Nested and e are visible
    override val b = 5 // 'b' is protected
    }
    class Unrelated(o: Outer) {
    // o.a, o.b are not visible
    // o.c and o.d are visible (same module)
    // Outer.Nested is not visible, and Nested::e is not visible either
    }

可继承声明

继承修饰符open(与java的final相对),使用Kotlin声明一个可以被继承的类必须冠以open