Kotlin 基礎-程式結構(上)
Kotlin 基礎-程式結構(上)
一、常量與變數
1.1 型別推導
在 Kotlin 中,只要是編譯器認識的型別,就可以自動推匯出變數的型別,不需要我們顯示的指定。
val a = "fancyluo" //推導 String val b = 666//推導 Int val c = a + b//推導 String
1.2 常量
Kotlin 中使用 value 的縮寫 val 來表示一個不可變的值型別,與 Java 中 final 的用法類似。
// Java public static final String NAME = "fancyluo" // Kotlin val NAME = "fancyluo"
以上的兩行程式碼在使用上來說是一樣的,如果你想重新給「NAME」賦值,是不被允許的,編譯器會報錯。 但是,它們本質上還是有區別的,下面引入一個概念 編譯期常量:值在編譯期就已經確定的常量,並且會把對它的引用全部替換為它的值。 Java 使用 final 定義的是編譯期常量,而 Kotlin 使用 val 定義的是不可變的值型別,也可以稱為執行時常量。如果想要在 Kotlin 中定義編譯期常量,那麼需要使用 const 關鍵字。
const val NAME = "fancyluo"
1.3 變數
Kotlin 中使用 variable 的縮寫 var 來表示變數,變數可以被重新賦值。
var x = "fancyluo" x = "HiphopMan"
二、函式
我們先來看看函式的語法,如下
- fun [函式名]([引數列表]):[返回值型別]{[函式體]} - fun [函式名]([引數列表]) = [表示式]
Kotlin 中的函式以 fun 開頭,下面以幾個例子來說明 Kotlin 函式的使用方法。
2.1 有返回值
Kotlin 中函式的返回值寫在引數列表的後面,以冒號加一個返回值的型別表示。
fun count(price: Int, sum: Int): Int { return price * sum }
如果一個函式只是返回一個表示式的值,那可以使用更簡潔的寫法,直接使用等號後面跟表示式即可。
fun count(price: Int, sum: Int): Int = price * sum
如果可以推匯出表示式的型別,那麼返回值也可以忽略不寫。
fun count(price: Int, sum: Int) = price * sum
2.2 無返回值
Kotlin 中函式如果沒有返回值,預設返回的是 Unit,類似於 Java 中的 void。Unit 本身沒什麼意義,平時開發中並不用顯示的指定,只要知道這麼一回事就好了。
fun printName(name:String):Unit{ println(name) }
當函式體為一個表示式的時候可以用簡化的寫法,這時候函式的返回值就是表示式的返回值,都是返回 Unit。
fun printName(name:String) = println(name)
2.3 匿名函式
匿名函式無需函式名,但必須賦值給一個變數或常量,否則編譯器會報錯。
var sum = fun(a: Int, b: Int) = a + b println(sum(6,6))
2.4 編寫函式的建議
1.遵循單一職責原則,功能要單一。
2.函式起名應該要顧名思義,儘量避免不符合規範的命名。
3.引數的個數不要太多。
三、Lambda 表示式
3.1 語法與示例
我們先來看看 Lambda 表示式的語法。
- {[引數列表] -> [函式體,最後一行是返回值]}
Lambda 表示式其實也就是匿名函式,下面看個例子。
// 匿名函式 var sum = fun(a: Int, b: Int) = a + b // Lambda 表示式 var sum = { a: Int, b: Int -> a + b } // 無參無返回值 var printName = { println("fancyluo") }
可以看到,上面定義的 Lambda 表示式有兩個引數 a 和 b,a + b 則為表示式的返回值,引數和返回值之間使用 -> 來分隔。如果 Lambda 表示式沒有返回值,那麼 -> 可以省略。 大家看到前面的例子會不會認為 Lambda 表示式只能寫一行呢?其實不然,函式體可以有多行,最後一行為 Lambda 表示式的返回值。
var sum = { a: Int, b: Int -> println("a + b = ${a + b}") a + b }
那麼 Lambda 表示式如何呼叫呢?使用 (),相當於執行了 invoke()。
println(sum(1, 2)) println(sum.invoke(1, 2))
3.2 Lambda 表示式的型別
在 Kotlin 中,函式也是一種型別,可以被賦值和傳遞
// 無參且返回值為 Unit 的函式型別:() -> Unit val printName = { print("fancyluo")} // 接收兩個整型引數且返回一個整型的函式型別:(Int,Int) -> Int val sum = { a: Int, b: Int -> a + b } // Array 的擴充套件方法 // 接收一個 T 型別引數並返回 Unit 型別的函式型別 public inline fun <T> Array<out T>.forEach(action: (T) -> Unit): Unit { for (element in this) action(element) }
前面我們說過,呼叫 Lambda 表示式就是呼叫其 invoke() 方法,而 Kotlin 在Functions.kt 檔案裡定義了 Function0 ~ Function22 這 23 個型別,Lambda 表示式的invoke() 方法接收幾個引數,叫表明它是 FuntionN 型別。以上面的例子來說,printName 就是 Function0 型別,sum 就是 Function2 型別。
// Function0 型別:() -> Unit public interface Function0<out R> : Function<R> { public operator fun invoke(): R } // Function2 型別:(Int,Int) -> Int public interface Function2<in P1, in P2, out R> : Function<R> { public operator fun invoke(p1: P1, p2: P2): R }
那如果我們定義了接收 23 個引數的 Lambda 表示式呢?那麼執行時就會丟擲找不到Function23 這個類的異常。
3.3 Lambda 表示式的簡化
當使用 Lambda 表示式作為函式的引數時,可以有很多簡化的寫法,下面一一演示。
// 完整寫法 intArrayOf(1, 2, 3, 4).forEach({ element -> println(element) }) // Lambda 表示式引數只有一個的時候,可以忽略不寫,使用 it 代替 intArrayOf(1, 2, 3, 4).forEach({ println(it) }) // 函式的最後一個引數是 Lambda 表示式,大括號可以移到括號外邊 intArrayOf(1, 2, 3, 4).forEach(){ println(it) } // 函式只有Lambda 表示式一個引數,小括號也可以省略 intArrayOf(1, 2, 3, 4).forEach{ println(it) } // forEach 引數型別:(T) -> Unit // println 函式型別:(Any) -> Unit // 入參、返回值與形參一致的函式可以用函式引用的方式作為實參傳入 intArrayOf(1, 2, 3, 4).forEach(::println)
最後再提一個問題,看如下程式碼。
fun main(args: Array<String>) { intArrayOf(1, 2, 3, 4).forEach { if (it == 3) return println(it) } println("這裡不會被列印") }
在 Lambda 表示式裡面使用 return 相當於 return 了 main 函式。如果只想終止迭代的話,需要使用標籤。
fun main(args: Array<String>) { intArrayOf(1, 2, 3, 4).forEach ForEach@ { if (it == 3) return@ForEach println(it) } println("這裡不會被列印") }