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