在 Kotlin 中,只要是編譯器認識的類型,就能夠自動推導出變量的類型,不須要咱們顯示的指定。bash
val a = "fancyluo" //推導 String
val b = 666 //推導 Int
val c = a + b //推導 String
複製代碼
Kotlin 中使用 value
的縮寫 val
來表示一個不可變的值類型,與 Java 中 final
的用法相似。函數
// Java
public static final String NAME = "fancyluo"
// Kotlin
val NAME = "fancyluo"
複製代碼
以上的兩行代碼在使用上來講是同樣的,若是你想從新給「NAME」賦值,是不被容許的,編譯器會報錯。 可是,它們本質上仍是有區別的,下面引入一個概念 編譯期常量:值在編譯期就已經肯定的常量,而且會把對它的引用所有替換爲它的值。 Java 使用 final 定義的是編譯期常量,而 Kotlin 使用 val 定義的是不可變的值類型,也能夠稱爲運行時常量。若是想要在 Kotlin 中定義編譯期常量,那麼須要使用 const 關鍵字。
ui
const val NAME = "fancyluo"
複製代碼
Kotlin 中使用 variable
的縮寫 var
來表示變量,變量能夠被從新賦值。this
var x = "fancyluo"
x = "HiphopMan"
複製代碼
咱們先來看看函數的語法,以下spa
- fun [函數名]([參數列表]):[返回值類型]{[函數體]}
- fun [函數名]([參數列表]) = [表達式]
複製代碼
Kotlin 中的函數以 fun
開頭,下面以幾個例子來講明 Kotlin 函數的使用方法。code
Kotlin 中函數的返回值寫在參數列表的後面,以冒號加一個返回值的類型表示。ip
fun count(price: Int, sum: Int): Int {
return price * sum
}
複製代碼
若是一個函數只是返回一個表達式的值,那可使用更簡潔的寫法,直接使用等號後面跟表達式便可。
element
fun count(price: Int, sum: Int): Int = price * sum
複製代碼
若是能夠推導出表達式的類型,那麼返回值也能夠忽略不寫。
開發
fun count(price: Int, sum: Int) = price * sum
複製代碼
Kotlin 中函數若是沒有返回值,默認返回的是 Unit
,相似於 Java 中的 void
。Unit
自己沒什麼意義,平時開發中並不用顯示的指定,只要知道這麼一回事就行了。編譯器
fun printName(name:String):Unit{
println(name)
}
複製代碼
當函數體爲一個表達式的時候能夠用簡化的寫法,這時候函數的返回值就是表達式的返回值,都是返回 Unit
。
fun printName(name:String) = println(name)
複製代碼
匿名函數無需函數名,但必須賦值給一個變量或常量,不然編譯器會報錯。
var sum = fun(a: Int, b: Int) = a + b
println(sum(6,6))
複製代碼
咱們先來看看 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))
複製代碼
在 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
這個類的異常。
當使用 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("這裏不會被打印")
}
複製代碼