---
tags: Kotlin
---
# Kotlin的keywords和operators
每次回來寫kotlin的時候都會忘記他的一些keywords和operators的用法,這邊簡單記錄幾個Kotlin特有且常用的,讓之後需要寫Kotlin的時候能更快恢復記憶。
## 官方網站
[Keywords and Operators](https://kotlinlang.org/docs/reference/keyword-reference.html)
## 常用的keywords
- var
可變變數
- val
不可變變數
- when
就是switch
```
when (x) {
1 -> print("x == 1")
2 -> print("x == 2")
else -> { // Note the block
print("x is neither 1 nor 2")
}
}
```
- fun
宣告function用的
```
fun double(x: Int): Int {
return 2 * x
}
```
- lateinit
讓var可以延後進行初值化
因為在Kotlin的世界中,class的properties必須一開始就被初值化,但有時候你就是沒辦法立即給一個值,可能你有相關依賴要等待之類的,這時候就可以用lateinit。而若是val需要延後進行initialize的話通常用下面提到的by lazy。
順帶一提,在使用Kotlin開發Android app的時候,不需要使用findviewbyid來將變數與view元件做綁定,直接使用view ID來操控該view就可以了,所以在Android的view上面不需要用lateinit也不需要by lazy。
- by
用來實現delegation pattern的keyword,可以簡單理解成[provided by](https://stackoverflow.com/a/57637851/11189726)。
by後面接的是要拿來委託做事的instance。
官方的範例是:
```
interface Base {
fun print()
}
class BaseImpl(val x: Int) : Base {
override fun print() { print(x) }
}
class Derived(b: Base) : Base by b
fun main() {
val b = BaseImpl(10)
Derived(b).print()
}
```
這個例子其實稍微太完整了一點,內容大概是它最後要用一個Derived這個class來做些事情,Derived這個class的其中一個功能是委託給type為Base的b來做,而這個Derived本身也是實作Base這個interface的class,以確保它有print()這個method。
另一個常用且比較簡短的例子是
```
val myLazyString: String by lazy { "Hello" }
```
- open
由於Kotlin預設所有class都是final的,所以要讓一個class可以被繼承的話就要先open它。
- in
- 用在for-loop
```for (i in 1..3)```
- 拿來判斷array裡面有無contain什麼元素
```if("value" in array)```
- 拿來判斷string裡面有無contain什麼substring
```if("substring" in string)```
- !in就是不包含的意思
- as
```val x: String = y as String```
- is
檢查type用的
- null
就是null,記錄一下免得忘了
- this
就是this,記錄一下免得忘了
## 常用的operators
- :
用於宣告、繼承以及函數回傳值型別的表達。宣告的時候:的左邊是變數名稱,右邊是型別;繼承的時候:的左邊是子class右邊是父class(小括弧有跟沒有都可以);表達函數回傳值型別的時候:左邊是函數的名字跟參數,就邊是回傳值的型別。
宣告:
```
val x: String
var a: String = "abc"
```
繼承:
```
// ex1
open class Shape {
open fun draw() { /*...*/ }
fun fill() { /*...*/ }
}
class Circle() : Shape() {
override fun draw() { /*...*/ }
}
// ex2
open class Shape {
open val vertexCount: Int = 0
}
class Rectangle : Shape() {
override val vertexCount = 4
}
```
表達函數回傳值型別:
```
fun sum(a: Int, b: Int): Int {
return a+b
}
```
- ?
Kotlin把變數有分為nullable(可能會是null)跟non-nuuable(不會是null)的,若用?宣告的話該變數就是nullable的。
```
var a: String = "abc" // Regular initialization means non-null by default
a = null // compilation error
var b: String? = "abc" // can be set null
b = null // ok
```
然後會常常看到變數後面接?,這時候意思是safe call。其實就是只要是nullable的變數在做操作的時候後面都要加一個?就對了。
```
val a = "Kotlin"
val b: String? = null
println(b?.length) // print "null"
println(a?.length) // print "6", Unnecessary safe call
```
- !!
會把變數變成non-null type,在runtime若發現該變數是null的話會丟出一個exception。
```
val l = b!!.length
```
- ?:
這叫做Elvis Operator,下兩行程式碼意思相等:
```
val l = b?.length ?: -1
val l: Int = if (b != null) b.length else -1
```
- ==
value相等判斷,跟常見的語言如C++、Java、Python的一樣,只有相同型別的能判斷,特別的是若是跟null判斷的話永遠都會得到false。順帶一提,Javascript的==會做型別轉換,比較不一樣。
- ===
reference相等判斷,用來判別兩個reference是否指向同一個object。順帶一提,Javascrip的===也跟這裡一樣是reference相等的判斷。
- ..
會產生一個range,常用於for-loop裡面,以下順便介紹until
```
if (i in 1..4) { // 1,2,3,4
print(i)
}
for (i in 1 until 4) { 1,2,3
print(i)
}
```
- ->
- 用在when裡面
- 用於function type的表達
```
(A, B) -> C
() -> A
(int, int) -> int
(int) -> Unit
```
上面程式碼中,左邊的是parameters的型別,右邊是回傳值的型別
右邊放Unit就是沒有回傳值。
- lambda expression
```
{ a, b -> a + b }
```
上面程式碼中,左邊的是parameters,右邊是函數內容
完整版的長得像下面的樣子:
```
val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }
```
具體例子如下方Android的Observer:
```
// Create the observer which updates the UI.
val nameObserver = Observer<String> { newName ->
// Update the UI, in this case, a TextView.
nameTextView.text = newName
}
```
這個Observer在Observable發送notification時會拿到一個string,也就是newName,此newName就是這個lambda裡面的parameter,然後把它用在lambda的內容裡去更新nameTextView的text。順帶一提,程式碼中Observer<String>的<String>是generic的表示法,表示這個Observer在implement的時候是用String帶入原本Observer<T>的T。
- $
用在string templates
```
val s = "abc"
println("$s.length is ${s.length}") // prints "abc.length is 3"
```
以上大概就是比較常用到的,其他的我還太菜目前比較少用到XD