Kotlin 基礎-程序結構(上)

1、常量與變量

1.1 類型推導

在 Kotlin 中,只要是編譯器認識的類型,就能夠自動推導出變量的類型,不須要咱們顯示的指定。bash

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 關鍵字。
ui

const val NAME = "fancyluo"
複製代碼

1.3 變量

Kotlin 中使用 variable 的縮寫 var 來表示變量,變量能夠被從新賦值。this

var x = "fancyluo"
x = "HiphopMan"
複製代碼

2、函數

咱們先來看看函數的語法,以下spa

- fun [函數名]([參數列表]):[返回值類型]{[函數體]}
- fun [函數名]([參數列表]) = [表達式]
複製代碼

Kotlin 中的函數以 fun 開頭,下面以幾個例子來講明 Kotlin 函數的使用方法。code

2.1 有返回值

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
複製代碼

2.2 無返回值

Kotlin 中函數若是沒有返回值,默認返回的是 Unit,相似於 Java 中的 voidUnit 自己沒什麼意義,平時開發中並不用顯示的指定,只要知道這麼一回事就行了。編譯器

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 編寫函數的建議

  • 遵循單一職責原則,功能要單一。
  • 函數起名應該要顧名思義,儘可能避免不符合規範的命名。
  • 參數的個數不要太多。

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 至關於 returnmain 函數。若是隻想終止迭代的話,須要使用標籤。

fun main(args: Array<String>) {
    intArrayOf(1, 2, 3, 4).forEach ForEach@ {
        if (it == 3) return@ForEach
        println(it)
    }
    println("這裏不會被打印")
}
複製代碼
相關文章
相關標籤/搜索