Kotlin 之表達式詳解

常量和變量

fun main() {
    //變量
    var a: Int = 2
    a = 3

    //只讀變量,在局部中,和 final 相同
    val b = 2
    //如果是全局
    val x = X()
    println(x.b) //每次的值都不一樣

    /**
     * 長量引用
     * 創建的對象在 堆 上
     * 對象內部內容可以改變,但是對象不能改變
     */
    val x1 = X()
}

/**
 * 常量
 * 只能定義在全局範圍
 * 只能修飾基本類型
 * 必須立即用字變量初始化
 * 和 java 中的 static final 基本相同
 */
const val b = 2 // 編譯時即可確定常量的值,並用值替換調用處
val c: Int  //運行時才能確定值
    get() {
        TODO()
    }


class X {
    //屬性
    val b: Int
        get() {
            return (Math.random() * 100).toInt()
        }
}

分支表達式

fun main() {

    var c = 4
    // if else 表達式
    c = if (c == 4) 3 else 9
    println(c)


    //分支,類似於 switch,但是不用寫 break
    when (c) {
        0 -> c = 2
        1 -> c = 3
        else -> c = 20
    }
    //簡化
    c = when (c) {
        0 -> 2
        1 -> 3
        else -> 20
    }

    //條件轉移到分支
    var x: Any = ""
    when {
        x is String -> x = "哈哈哈"
        x is Int -> x = 10
        else -> x = 90
    }
    //簡化
    x = when (x) {
        is String -> "哈哈哈"
        is Int -> 10
        else -> 90
    }

    //when...
    x = when (val input = readLine()) {
        null -> ""
        else -> input.length
    }

    //try ... catch 表達式
    x = try {
        3 / 0
    } catch (e: Exception) {
        e.printStackTrace()
        0
    }

}

運算符

  • Kt 中支持運算符重載

  • 運算符的範圍僅限官方指定的符號

    指定的符號

​ Kt 允許我們爲自己的類型提供預定義的一組操作符的實現,這些操作符舉要固定的符號表示,如 + * 等。爲實現這樣的操作符,Kt 爲相應的類型提供了一個固定名字的成員函數或者擴展函數。重載操作符需要使用 operator 修飾符標記。

​ 如下:

fun main() {
    val point = Point(10, 20)
    println(point - 10) //0
}

class Point(val x: Int, val y: Int) {
    //重載 - 號
    operator fun minus(num: Int): Int {
        return x - num
    }
}
fun main() {
    val point = Point(10, 20)
    println(point[0]) //10
    println(point[1]) //20
    println(point[2]) //java.lang.IndexOutOfBoundsException
}

class Point(val x: Int, val y: Int) {
    //重載 get
    operator fun get(index: Int): Int {
        return when (index) {
            0 -> x
            1 -> y
            else -> throw IndexOutOfBoundsException()
        }
    }
}

官方中文文檔

中綴表達式

fun main() {

    println("Hello" to "Word")
}

/**
 * 中綴表達式
 * 必須加 infix 標識
 * 只有一個參數,並且是擴展方法
 */
infix fun String.rotate(str: String): String {
    return this + str
}

函數的表達式形式

fun main() {

    println(add(1, 2))
    println(add2(2, 3))

}


fun add(x: Int, y: Int): Int {
    return x + y
}

//如果函數中只有一句或者爲一個表達式,可以這樣寫
fun add2(x: Int, y: Int): Int = x + y

Lambad 表達式

fun main() {


    /**
     * 將匿名函數賦值給一個變量
     * fun1 是變量名
     * 調用 fun1()
     */
    val fun1 = fun() {
        println("匿名函數")
    }

    //Lambad 其實就是匿名函數
    val l1 = {
        println("lambad")
    }

    //帶參數的 Lambad
    val l2 = { p: Int ->
        println("帶參數的 Lambad")
    }

    // 表達式中最後一行爲返回值,可不加 return
    val l3 = { p: Int ->
        println(p)
        "Hello Word"
    }

    //表達式中如果只有一個參數,可以用 it 代替
    val l4: Function1<Int, Unit> = {
        println(it)
    }

    l4(123)

    //第二個參數接收一個Lambad 表達式,接收一個 Int 參數,並返回一個 Int 參數
    IntArray(2) { i ->
        0
    }
    fun3() { x: Int, y: Int ->
        println("${x + y}")
        "$x + $y"
    }
}

//接收兩個 int 類型,返回一個 String 類型的函數
fun fun3(sum: (Int, Int) -> String) {
    println(sum(2, 3))
}

fun fun0() {
    println("普通函數")
}

案例1

實現 equals 和 hashCode


fun main() {

    val hashSet = hashSetOf<Person>()
    (0..5).forEach { _ ->
        hashSet += Person(30, "張三")
    }

    println(hashSet.size)

    //注意:將對象添加到集合後就不要改變對象的數據,否則會造成無法刪除,從而引發內存泄露
}


class Person(private val age: Int, private val name: String) {
    override fun equals(other: Any?): Boolean {
        val o = (other as? Person) ?: return false
        return age == o.age && name == o.name
    }

    override fun hashCode(): Int {
        return 31 + age * 7 + name.hashCode()
    }
}

案例2

實現 String 的四則運算

fun main() {

    val value = "HelloWorld"
    println(value - "World")
    println(value * 3)
    println(value / "l")

}

// - 替換第一個出現的字符串
operator fun String.minus(right: Any?): String =
    this.replaceFirst(right.toString(), "")

// * 鏈接一個字符串
operator fun String.times(count: Int): String {
    return (1..count).joinToString(" ") { this }
}

// / 找出出現多少次
operator fun String.div(right: Any?): Int {
    val r = right.toString()
    //根據傳入的字符串,從 this 中挨個進行查找
    //如 length = 2,那就是 " he , el ,ll ,lo , ow ... "
    //最後一個參數是表達式,所以可以移到外面
    return this.windowed(r.length, 1) {
        //判斷是否相等
        it == r
    }.count {
        //計數,
        it
    }
}

總結

  • 常量和變量
    • 定義方式:var / val /const val
    • 常量按類型分類
      • 常量值
      • 常量引用
    • 常量按時期分類
      • 編譯器常量
      • 運行時常量
  • 分支表達式
    • if else
    • when …
    • try … catch
  • 運算符
    • 常見的運算符
      • “+ - * /”
      • “. < ==”
      • “ in ”
      • " get "
      • " invoke "
    • 運算符的重載
    • 中綴表達式:必須有 infix 標識,是擴展方法,並且只有一個參數
    • 函數的表達式形式:如果函數中只有一句話或者一個表達式,可直接賦值給 函數
  • Lambad
    • 匿名函數 :本質是匿名函數,匿名函數不能直接使用,需要一個變量來接收,然後調用這個變量就能間接的調用這個匿名函數
    • 寫法
    • 類型
    • 類型推斷:如果左邊定義中已經寫了具體的類型聲明,後面的實現就可以不用寫。反之,後面則需要具體的聲明

參考自慕課網 Kotlin 從入門到精通

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章