知识点

1.kotlin主函数入口 kotlin方法

2.变量 注释 string 模板 条件表达式 空值检测 类型检测与自动类型转换 使用For循环  使用while循环 使用when表达式 使用区间 集合 创建类

笔记

package com.example.lib.d01start

// 0 写在前面的话
// 将Kotlin转为Java步骤:
// Tools → Kotlin icon Kotlin → Show Kotlin Bytecode
// Decompile
// 会将Kotlin Code的二进制转为Java Code 方便对比学习

// 同时可以在Android studio中将java code转换为kotlin code
// 选择Java file 右键 convert java file to kotlin file
// 一时不知道kotlin的语法 可以先写java 再转为kotlin
// 甚至可以先写好Java 的代码 直接copy到Kotlin文件中
// Android Studio 会检测到剪切板是Java Code 询问你是否将Java代码转换为Kotlin代码
// 点击确认 可以直接转换

// 1 kotlin程序的入口
// 与普通的Java文件不同 写在类外部
fun main() {
    println("Hello World")
    // 2 Kotlin函数的学习
    method();
}

fun method() {
    println(sum(13, 14));
    println(sum1(14, 14));
    println(printSum(13,15))
    println(printSum1(33,22))
}

// kotlin方法的定义
/*
    方法关键字 方法名(参数1:参数1类型,参数2:参数2类型...):返回值类型{
      方法体
    }
*/
fun sum(a: Int, b: Int): Int {
    println("start $a+$b")
    return a + b
}

// 如果方法体内部只有一句话 可以简写成如下
// 返回类型可以推断 “=”类似"return"
fun sum1(a: Int, b: Int) = a + b

// 像sum方法内部有两行代码 无法缩写成sum1的样子
//fun sum2(a: Int, b: Int) = println("start $a+$b") a + b// 报错

// Unit 无意义的值 类似于 void
fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a + b}")
}

// Unit类型可以忽略不写
// 方法体内部的$a $b代表变量的实际值
// ${a + b} {}内部是一个表达式
// 如果返回值类型是Unit 还会打印kotlin.Unit的信息
fun printSum1(a: Int, b: Int) {
    println("sum1 of $a and $b is ${a + b}")
}

class D01Start {

}
package com.example.lib.d01start

import java.lang.NumberFormatException
import java.util.*

fun main() {
    // 3 变量
    variable()
    // 4 注释 略
    // 5 string 模板
    stringTemplate()
    // 6 条件表达式
    condition()
    // 7 空值检测
    nullCheck()
    // 8 类型检测与自动类型转换
    typeCheck();
    // 9 使用For循环
    useFor();
    // 10 使用while循环
    useWhile();
    // 11 使用when表达式
    val param = 1.2
    useWhen(param)
    // 12 使用区间
    useRange(8)
    useRange(14)
    useRange2()
    useRangeTravels()
    // 13 集合
    useCollection()
    // 14 创建类
    val person = Person("zhangsan",25)
    person.printPerson()
}

class Person constructor(name:String,age:Int) {
    val mName = name
    val mAge = age
    fun printPerson(){
        println("name is $mName, age is $mAge")
    }
}


fun useCollection() {
    val list = listOf("a", "b", "c", "orange")
    // 第一种遍历
    for (item in list) {
        println(item)
    }

    // 第二种遍历
    list.forEach { println(it) }

    // 第三种遍历
    for (index in list.indices) {
        println(list[index])
    }

    // switch case
    when {
        "orange" in list -> println("juicy")
        "apple" in list -> println("apple is fine too")
    }

    // 使用 lambda 表达式来过滤(filter)与映射(map)集合:
    val fruits = listOf("banana", "avocado", "apple", "kiwifruit", "aaa")
    fruits
            .filter { it.startsWith("a") } // 过了所有以a开头的集合
            .sortedBy { it } // 排序
            .map { it.uppercase(Locale.getDefault()) }// 转化为大写
            .forEach { println(it) } // 输出
}

fun useRangeTravels() {
    // 输出1-5
    for (x: Int in 1..5) {
        print(x)
    }
    println()
    // 输出13579
    for (x in 1..10 step 2) {
        print(x)
    }
    println()
    // 降序输出
    for (x in 9 downTo 0 step 3) {
        print(x)
    }
}

fun useRange2() {
    // 创建 String数组
    val list = listOf("a", "b", "c")

    if (-1 !in 0..list.lastIndex) {
        println("-1 is out of range")
    }
    println("list.size = ${list.size}")
    println("list.indices = ${list.indices}")
    if (list.size !in list.indices) {
        println("list size is out of valid list indices range, too")
    }

    if (2 in list.indices) {
        println("2 is in valid list indices range")
    }
}

// 使用 in 运算符来检测某个数字是否在指定区间内
fun useRange(i: Int) {
    if (i in 1..10) {
        println("fits in range")
    } else {
        println("not in range")
    }
}

// kotlin 版本的switch case
fun useWhen(obj: Any) {

    when (obj) {
        1 -> println("One")
        "Hello" -> println("Greeting")
        is Long -> println("Long")
        !is String -> println("Not a string")
        else -> println("Unknown")
    }
}

fun useWhile() {
    val items = listOf("apple", "banana", "kiwi")
    var index = 0
    while (index < items.size) {
        println("item at $index is ${items[index]}")
        index++
    }

    index = 0
    while (index in items.indices) {
        println("item at $index is ${items[index]}")
        index++
    }
}

fun useFor() {
    // 增强for循环版本
    for1()
    // 角标访问版本
    for2()
}

fun for1() {
    // 类似于
    // val items: List<String> = ArrayList(Arrays.asList("aaa", "bbb"))
    val items = listOf("apple", "banana", "kiwi")
    // kotlin中的遍历关键字in
    // 这里省略了item的声明
    for (item in items) {
        println(item)
    }
}

fun for2() {
    val items = listOf("apple2", "banana2", "kiwi2")
    // 类似于使用角标访问数组
    for (index in items.indices) {
        println("item at $index is ${items[index]}")
    }
}

//在使用is关键字内部 不需要再进行强制转换 在特定分支中 参数就是指定类型
fun typeCheck() {
    // kotlin 可以在方法中定义方法
    fun printLength1(obj: Any) {
        // 打印某个对象的字符串长度
        // ${getStringLength(obj) ?: "... err, not a string"} 花括号内是一个表达式
        // ?: 看起来是java三元操作符的简写 实际是个判空操作符 ?:前面的如果不是空 直接使用这个值 否则使用?:后面的值
        println(" $obj string length is ${getStringLength(obj) ?: "... err, not a string"} ")
    }

    printLength1("Incomprehensibilities")
    printLength1(1000)
    printLength1(listOf(Any()))
}

fun getStringLength(obj: Any): Int? {// Any代表任意类型 相当于Java的Object
    // is 相当于Java中的instanceof
    if (obj is String) {
        // `obj` 在该条件分支内自动转换成 `String`类型
        return obj.length
    } // 在离开类型检测分支后,`obj` 仍然是 `Any` 类型
    return null
}

fun nullCheck() {
    // 当某个变量的值可以为 null 的时候,必须在声明处的类型后添加 ? 来标识该引⽤可为空
    println("parseInt ==> " + stringToInteger("ww"))
    println("parseInt ==> " + stringToInteger("12"))
    printProduct("w", "2")
}

// 使用?表明 返回值可能为空
fun stringToInteger(s: String): Int? {
    // 用到了Kotlin中使用try catch
    return try {
        Integer.valueOf(s)
    } catch (e: NumberFormatException) {
        null
    }
}

fun printProduct(arg1: String, arg2: String) {
    val x = stringToInteger(arg1)
    val y = stringToInteger(arg2)
    // 直接使⽤ `x * y` 会导致编译错误, 因为它们可能为 null
    if (x != null && y != null) {
        // 在空检测后, x 与 y 会⾃动转换为⾮空值(non-nullable)
        println(x * y)
    } else {
        println("'$arg1' or '$arg2' is not a number")
    }
}

fun condition() {
    println("max is :" + maxOf(2, 3))
    println("max is :" + maxOf2(2, 3))
}

fun maxOf(a: Int, b: Int): Int {
    if (a > b) {
        return a
    } else {
        return b
    }
}

// 这里使用了第一节在函数时使用的简写
fun maxOf2(a: Int, b: Int) = if (a > b) a else b


// const 代表运行时常量
// 这里是顶层
// 相当于 public static final double MY_CONSTANT
const val MY_CONSTANT = 3.1415

fun variable() {
    // 变量声明的最常见方式
    // 变量 变量名:变量类型 = 赋值
    val a: Int = 1 // ⽴即赋值

    // 省略变量类型的声明 可以通过自动推断推断出类型
    val b = 2 // ⾃动推断出 `Int` 类型


    val c: Int // 如果没有初始值类型不能省略
    c = 3 // 明确赋值
    println(c)

    // 使用var来声明可变的变量
    var x = "String"
    println(x)
    x = "new String"
    println(x)

    // 使用val来声明不可变的变量 val有点像final关键字 但不完全相等
    val y = "String1111"
    //y = "new String1"//报错 Val cannot be reassigned

    // val 代表运行时常量
    // 相当于 final double PI
    val pi = 3.14
    println(pi)
    println(MY_CONSTANT)
}

fun stringTemplate() {
    var a = 1
    // $a代表打印变量中的真实的值
    // 并且该次赋值以后 即使a的值变化了 s1的内容也不再变化
    val s1 = "a is $a"
    println(s1)
    // 给变量a赋值新值2
    a = 2
    // 输出 now a is 2 and s1 is a is 1
    println("now a is $a and s1 is $s1")

    // ${}内部是一个表达式 调用了 String的replace方法
    val s2 = "${s1.replace("is", "was")}, but now is $a"
    // 输出 a was 1, but now is 2
    println(s2)
}

class D02Start {

}

第二章 基础

知识点

章节:基本类型 包 控制流 返回与跳转

1. 基本类型 字面常量 显示转换 运算 数字比较 字符 布尔 数组 (⽆符号类型 跳过 因为他们似乎还不稳定) string

2.as 关键字

3.if 表达式  when 表达式 for 循环遍历 while 循环

4.return break continue的典型用法 学习使用标签 标签的隐式用法 返回标签时带有返回值

笔记

package com.example.lib.d02basic

/**
 * 数据类型
 * Java中char可以与数字进行比较 但是Kotlin中不行
 * char a = 'a';
 * if (a>10) System.out.println(a);
 *
 *
 */

// 十进制
const val NUMBER1 = 123

// 16进制的17
const val NUMBER2 = 0x11

// 2进制的5
const val NUMBER3 = 0b0101
// Kotlin 不支持八进制


fun main() {
    // 基本类型
    basicType()
    // 字面常量
    valVariable()
    // 显示转换
    explicitConvert()
    // 运算
    calculate()
    // 数字比较
    numberCompare()
    // 字符
    char()
    // 布尔
    bool();
    // 数组
    array()
    // ⽆符号类型 跳过 因为他们似乎还不稳定
    // String
    string()
}

fun string() {
    val string1: String = "This is String"
    // 利用for循环 输出字符串
    for (char in string1) {
        println(char)
    }
    println(string1)
    val s = "abc" + 1
    // 字符串拼接
    println(s + "def")
    // 与上面等价
    println("${s}def")

    val i = 10
    // 字符串模板
    println("i = $i")

    val s2 = "abc"
    // ⽤花括号括起来的任意表达式(花括号内部是一个表达式)
    println("$s2.length is ${s2.length}")

    val beef = "beef"
    val price = "99"
    println("$beef is $$price")
}

fun array() {
    val arrayOfInt: IntArray = intArrayOf(1, 3, 5, 7, 9)
    // 创建⼀个 Array<String> 初始化为 ["0", "1", "3", "4", "5"]
    val asc = Array(5) { element -> element }
    // 利用数组自带的iterator遍历
    asc.forEach { println(it) }


    /**整型Int的数组*/

    arrayOfInt.forEach { println(it) }
    /**字符Char类型的数组*/
    val arrayOfChar: CharArray = charArrayOf('H', 'e', 'l', 'l', 'o', 'W', 'o', 'r', 'l', 'd')
    arrayOfChar.forEach { println(it) }
    /**字符串String数组*/
    val arrayOfString: Array<String> = arrayOf("Hello", "World")
    for (element in arrayOfString) {
        println(element)
    }

    // ⼤⼩为 5、 值为 [0, 0, 0, 0, 0] 的整型数组
    val arr1 = IntArray(5)
    arr1.forEach { print("$it ") }
    println()
    // 例如: ⽤常量初始化数组中的值
    // ⼤⼩为 5、 值为 [42, 42, 42, 42, 42] 的整型数组
    val arr2 = IntArray(5) { 42 }
    arr2.forEach { print("$it ") }
    println()
    // 例如: 使⽤ lambda 表达式初始化数组中的值
    // ⼤⼩为 5、 值为 [0, 1, 2, 3, 4] 的整型数组(值初始化为其索引值)
    val arr3 = IntArray(5) { it * 1 }
    arr3.forEach { print("$it ") }
    println()
}

//三个引号"""括起来的字符串 内部没有转义并且可以包含换⾏以及任何其他字符
val definitionArray =
        """
public class Array<T> {
    /**
     * 数组的定义类 摘自Array.kt
     *
     *
     * Creates a new array with the specified [size], where each element is calculated by calling the specified
     * [init] function.
     * 创建一个指定长度的新数组 每一个元素可以被指定的init方法计算
     *
     * The function [init] is called for each array element sequentially starting from the first one.
     * It should return the value for an array element given its index.
     * init方法被每一个元素从第一个元素开始依次调用 它应该返回元素下标的值
     */
    public inline constructor(size: Int, init: (Int) -> T)

    /**
     * get方法 返回指定下标的元素
     * Returns the array element at the specified [index]. This method can be called using the
     * index operator.
     * ```
     * value = arr[index]
     * ```
     *
     * If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
     * where the behavior is unspecified.
     */
    public operator fun get(index: Int): T

    /**
     * set方法
     * Sets the array element at the specified [index] to the specified [value]. This method can
     * be called using the index operator.
     * ```
     * arr[index] = value
     * ```
     *
     * If the [index] is out of bounds of this array, throws an [IndexOutOfBoundsException] except in Kotlin/JS
     * where the behavior is unspecified.
     */
    public operator fun set(index: Int, value: T): Unit

    /**
     * 返回数组长度
     * Returns the number of elements in the array.
     */
    public val size: Int

    /**
     * 创建用于遍历数组的迭代器
     * Creates an [Iterator] for iterating over the elements of the array.
     */
    public operator fun iterator(): Iterator<T>
}
"""


fun bool() {
    val a = true
    val b = false
    println(a || b)
    println(a && b)
    println(!a)
}

fun char() {
    /*val a:Char = 'a'
    if (a == 1){ //Operator '==' cannot be applied to 'Char' and 'Int'

    }*/
    val b: Char = '1'
    println(b)

    //\t转义制表符
    //\b转义退格键
    //\n转义换行
    //\r转义回车符 不过没看懂效果。。
    //\'转义单引号
    //\"转义双引号
    //\\转义斜杠
    //\$转义美元符号
    val c: String = "aa \t bb\b cc\n dddddd \r ee \' ff \" gg\\ hh\$ "
    println(c)

    val d: Char = '5'
    println(decimalDigitValue(d))

    val e: Char = 'e'
    println(isSmallChar(e))

    val f: Char = 'F'
    println(isBigChar(f))
}

fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9') {
        throw IllegalArgumentException("Out of range")
    }
    return c.code - '0'.code // 利用数字在Unicode字符表里面的index位置 显式将char转换为数字
}

fun isSmallChar(c: Char): Boolean {
    return c in 'a'..'z'
}

fun isBigChar(c: Char): Boolean {
    return c in 'A'..'Z'
}

fun numberCompare() {
    val a = 1.0
    val b = 2.0
    val c = 3.0
    println(a == b)
    println(a + b == c)
    println(a != b)
    println(a < b)
    println(a > b)
    println(a <= b)
    println(a >= b)
    // 上述几个比较操作符是所有数字类型通用的
    val e = 5
    println(e in 1..10)
    println(e !in 1..10)
    // in !in是区间判断符号 只能用在Int或者char数值上
}

fun calculate() {
    val x = 5 / 2 // 与Java一样 整数相除还是整数 因此x是Int类型
    // println(x == 2.5) Operator '==' cannot be applied to 'Int' and 'Double'
    println(x == 2) // true

    val y = 5L / 2 // Long 与 Int运算 得到Long类型
    println(y == 2L)

    val u = 5 / 2.0 // 自动推断类型为Double
    println(u == 2.5)

    val w = 5 / 2.toDouble() // 显示转换为Double
    println(w == 2.5)

    val v = 5 / 2f // 显示转换为float
    println(v == 2.5f)

    // 位运算 对1 有符号左移2位 与上16进制的
    val b = 0b1100
    println(b)
    // 1 shl 2 = 0100
    // 1100 & 0100 == 0100
    val a = (1 shl 2) and b
    println(a)

    /**
    其他位运算
    shl(bits) – 有符号左移
    shr(bits) – 有符号右移
    ushr(bits) – ⽆符号右移
    and(bits) – 位与
    or(bits) – 位或
    xor(bits) – 位异或
    inv() – 位⾮
     */
}

fun explicitConvert() {
    /*
    val a: Int? = 1 // ⼀个装箱的 Int (java.lang.Integer)
    val b: Long? = a // 编译出错 无法将Int的对象赋值给Long

    val c: Long? = 1L // ⼀个装箱的 Long (java.lang.Long)
    val d: Int? = c // 编译出错 无法将Long的对象赋值给Int
    */
    /*
    以下为Java代码
    上面的Kotlin代码应该和当前的第一部分的Java Code类似
    Integer a = 1; // ⼀个装箱的 Int (java.lang.Integer)
    Long b = a; // 编译出错 无法将Int的对象赋值给Long

    Long c= 1L; // ⼀个装箱的 Long (java.lang.Long)
    Integer d= c; // 编译出错 无法将Long的对象赋值给Int

    int a = 1; // ⼀个装箱的 Int (java.lang.Integer)
    long b = a; // 可以编译

    long c= 1L; // ⼀个装箱的 Long (java.lang.Long)
    int d= c; // 编译出错 不能将long赋值给int
    */

    val b: Byte = 1 // OK, 字⾯值是静态检测的
    // val i: Int = b // 错误 较⼩的类型不能隐式转换为较⼤的类型
    val i: Int = b.toInt() // OK: 显式拓宽
    println(i)
    /**
    每个数字类型⽀持如下的转换:
    toByte(): Byte
    toShort(): Short
    toInt(): Int
    toLong(): Long
    toFloat(): Float
    toDouble(): Double
    toChar(): Char
     */
    // 虽然赋值和参数使用上没有隐式转换 但是算术运算会有重载做适当转换
    val l = 1L + 3 // Long + Int => Long 不会出错
    println(l)
}

fun valVariable() {
    // 数字字⾯值中的下划线(⾃ 1.1 起)
    val oneMillion = 1_000_000
    val creditCardNumber = 1234_5678_9012_3456L
    val socialSecurityNumber = 999_99_9999L
    val hexBytes = 0xFF_EC_DE_5E
    val bytes = 0b11010010_01101001_10010100_10010010

    // 定义一个Int值 为100
    val a: Int = -128
    // 定义一个可空的Int值 将a赋值给它
    val boxedA: Int? = a
    // 定义另一个可空的Int值 将a赋值给它
    val anotherBoxedA: Int? = a
    // 定义一个Int值 为10000
    val b: Int = 10000
    // 定义一个可空的Int值 将b赋值给它
    val boxedB: Int? = b
    // 定义另一个可空的Int值 将b赋值给它
    val anotherBoxedB: Int? = b
    // 这里涉及Kotlin中的==和===的差别
    // ==相当于java的equals
    // ===相当于java的== 是地址比较
    // 至于第一次输出是true 第二次是false 是因为Kotlin和Java一样 在内部保存了一些常量
    // 如果新创建的Integer 属于区间[-128,127] 则会从常量池取出数据赋值
    // 否则new一个新的Integer
    // 具体可以参照
    // 书里面的同⼀性应该指 地址比较相同
    // 相等性指他们的equals方法返回的结果
    println(boxedA === anotherBoxedA) // true
    println(boxedB === anotherBoxedB) // false

    println(boxedA == anotherBoxedA) // true
    println(boxedB == anotherBoxedB) // true
}

fun basicType() {
    // 未超出 Int 最⼤值的整型值初始化的变量都会推断为 Int 类型
    val one = 1 // Int
    // 如果初始值超过了其最⼤值,那么推断为 Long 类型
    val threeBillion = 3000000000 // Long
    // 显式指定 Long 型值
    val oneLong = 1L // Long
    // 显式指定 Byte 型值
    val oneByte: Byte = 1

    // 以⼩数初始化的变量,编译器会推断为 Double 类型
    val e = 2.7182818284 // Double
    // 显式指定为 Float 类型
    val eFloat = 2.7182818284f // Float

    val eee = 2.7182818284f// 实际是Float 不会转换为double //Java中这么写 实际值是double类型 double myD = 2.7182818284f;

    fun printDouble(d: Double) {
        print(d)
    }

    // Kotlin 中的数字没有隐式拓宽转换
    val i = 1 // Int 类型
    val d = 1.1 // double 类型
    val f = 1.1f // float 类型
    printDouble(d)
    // printDouble(i) // 错误: 类型不匹配
    // printDouble(f) // 错误: 类型不匹配
}

class D02Basic01BasicType {

}
package com.example.lib.d02basic
// as 关键字
import java.io.File as MyFile // MyFile 代表“java.io.File”

fun main() {
    val file = MyFile("filename")
//    val pa = MyPattern()
    val d03 = D02Basic02Package()
}

class D02Basic02Package {

}
package com.example.lib.d02basic


fun main() {
    // if 表达式
    conditionIf()
    // when 表达式
    conditionWhen()
    // for 循环遍历
    conditionFor()
    // while 循环
    conditionWhile()
}

fun conditionWhile() {
    testWhile()
    testDoWhile()
}

fun testDoWhile() {
    var parameter = 5
    do {
        parameter--
        println(parameter)
    } while (parameter > 0)
}

fun testWhile() {
    var parameter = 5
    while (parameter > 0) {
        parameter--
        println(parameter)
    }
}

fun conditionFor() {
    val arrayOfString: Array<String> = arrayOf("Hello", "World","Kotlin")
    // 经典for循环
    classicTraverse(arrayOfString)
    // iterator遍历
    iteratorTraverse(arrayOfString)
    val arrayOfInt: IntArray = intArrayOf(11, 14, 17)
    // 区间表达式的for循环
    intervalExpressionTraverse()
    // 下标遍历
    indexTraverse(arrayOfString)
    // withIndex 遍历
    withIndexTraverse(arrayOfString)
}

fun withIndexTraverse(arrayOfString: Array<String>) {
    for ((index, value) in arrayOfString.withIndex()) {
        println("the element at $index is $value")
    }
}

fun indexTraverse(arrayOfString: Array<String>) {
    for (i in arrayOfString.indices) {
        println(arrayOfString[i])
    }
}

fun intervalExpressionTraverse() {
    // 输出1 2 3
    for (element in 1..3) {
        println(element)
    }
    // 从6 降序到0 步长2 输出6 4 2 0
    for (i in 6 downTo 0 step 2) {
        println(i)
    }
}

fun iteratorTraverse(arrayOfString: Array<String>) {
    val iterator =  arrayOfString.iterator()
    while (iterator.hasNext()){
        println(iterator.next())
    }
}

fun classicTraverse(arr: Array<String>) {
    for (item in arr) {
        println(item)
    }
}

// when 语句相当于Java中的switch case
fun conditionWhen() {
    // when 作为表达式使用
    println(expression(2))
    // when 作为表达式使用 所有分支已经覆盖可能结果
    println(expression2(false))
    // when 不作为作为表达式使用
    sentence(2)
    // when 表达式也可以将条件合并
    multiCondition(1)
    // 我们可以甚至可以用方法(⽽不只是常量)作为分⽀条件
    println(expressionAsCondition("hello"))
    println(expressionAsCondition("hello1"))
    // 我们可以⽤任意表达式(⽽不只是常量)作为分⽀条件
    expressionAsCondition2(11)
    expressionAsCondition2(1)
    // when里面的类型推断
    println(hasPrefix(1))
    println(hasPrefix("prefix"))
    // when 表达式是bool值
    boolWhen(1, 3)
}

fun boolWhen(x: Int, y: Int) {
    when {
        isEven(x) -> println("x is isEven")
        isEven(y) -> println("y is isEven")
        else -> println("x y are Odd.")
    }
}

fun isEven(x: Int): Boolean {
    return x % 2 == 0
}


// 判断字符串是否以prefix打头
// 将when表达式的值直接赋值给方法返回值
fun hasPrefix(x: Any): Boolean = when (x) {
    // is String == true后 该分支里面 x是String类型的
    is String -> x.startsWith("prefix")
    else -> false
}

fun expressionAsCondition(x: String): String {
    // 我们可以⽤任意表达式(甚至是方法作为分支条件 ⽽不只是常量)作为分⽀条件
    val str: String = "test"
    return when (x) {
        getResString(str) -> "greeting"
        else -> "none of the above"
    }
}

fun getResString(param: String): String {
    return if (param == "test") {
        "hello"
    } else {
        "unknown"
    }
}

val arrayOfInt: IntArray = intArrayOf(11, 14, 17)
fun expressionAsCondition2(x: Int) {
    // 我们可以⽤任意表达式(⽽不只是常量)作为分⽀条件
    when (x) {
        in 1..10 -> print("x is in the range")
        in arrayOfInt -> print("x is valid")
        !in 10..20 -> print("x is outside the range")
        else -> print("none of the above")
    }
}

fun parseInt(s: String): Int {
    TODO("Not yet implemented")
}

fun multiCondition(x: Any) {
    when (x) {
        // when 表达式也可以将条件合并
        0, 1 -> println("x == 0 or x == 1")
        else -> println("otherwise")
    }
}

fun sentence(obj: Any) {
    // when 不作为作为表达式使用(不使用when的返回结果) 可以没有else分支
    when (obj) {
        1 -> println("x==1")
        2 -> println("x==2")
    }
}

fun expression(obj: Any): String {
    // when 作为表达式使用(使用when的返回结果) 必须有else分支 除非所有分支已经覆盖可能结果
    return when (obj) {
        1 -> "x==1"
        2 -> "x==2"
        else -> { // 注意这个块
            "unknown"
        }
    }
}

fun expression2(obj: Boolean): String {
    // when 作为表达式使用(使用when的返回结果) 必须有else分支 除非所有分支已经覆盖可能结果
    return when (obj) {
        true -> "true..."
        false -> "false..."
    }
}

fun conditionIf() {
    // 传统⽤法
    val a = 10
    val b = 12
    var max1: Int = a
    if (a < b) max1 = b
    // With else
    val max2: Int
    if (a > b) {
        max2 = a
    } else {
        max2 = b
    }
    // if本身是一个表达式 可以将他的结果传入参数
    val max3 = if (a > b) {
        println("Choose a")
        a
    } else {
        println("Choose b")
        b
    }

    // val max4 = if (condition) A else B
    // 如果condition成立 max4 = A 否则 max4 = B
    println(max3)
}

class D02Basic03Contrl {

}
package com.example.lib.d02basic

/**
 * Kotlin 有三种结构化跳转表达式:
 * return。默认从最直接包围它的函数或者匿名函数返回。
 * break。终⽌最直接包围它的循环。
 * continue。继续下⼀次最直接包围它的循环。
 */

fun main() {
    // 测试return
    testReturn(null)
    testReturn("aa")
    // break continue的典型用法
    classicBreakContinue()
    // 学习使用标签
    testLabel()
    // testLabel1 vs testLabel2 标签的意义
    testLabel1()
    testLabel2()
    // 标签的隐式用法
    testLabel3()
    // testLabel3的另外一种写法
    testLabel4()
    // 模拟Break
    mockBreak()
    // 返回标签时带有返回值
    println(returnLabel(listOf(1, 1, -1)))// 输出[]
    println(returnLabel(listOf(1, 0, 1)))// 输出[number 1, zero, number 1]
}

/**
 * 该方法用于理解
 * 当要返⼀个回值的时候,解析器优先选⽤标签限制的 return,即
 * return@a 1
 * 意为“返回 1 到 @a ”,⽽不是“返回⼀个标签标注的表达式 (@a 1) ”。
 *
 * 传入的参数里面只要有-1 就会返回空list 有0的则返回结果 不会出现"number 0"而是出现"zero"
 */
fun returnLabel(ints: List<Int>): List<String> {
    return ints.map label@{
        if (it == 0) return@label "zero" // return at named label 返回到标签
        if (it == -1) return emptyList() // return at returnLabel 返回整个方法
        "number $it" // expression returned from lambda 返回的表达式
    }
}

//foo(listOf(1, -1, 1)) // []
//foo(listOf(1, 0, 1)) // ["number 1", "zero", "number 1"]

fun mockBreak() {
    // run:Calls the specified function block and returns its result.
    // run:调用指定方法块并返回其结果
    run loop@{
        listOf(1, 2, 3, 4, 5).forEach {
            if (it == 3) return@loop // 从传⼊ run 的 lambda 表达式⾮局部返回
            // 意思应该是返回到run方法调用处而不是退出整个方法 关系到print(" done with nested loop")能否被调用
            // 虽然break只能在循环中使用('break' and 'continue' are only allowed inside a loop) 在
            // 普通的代码中 用return+label的方式可以模拟break的作用
            println(it)
        }
    }
    print(" done with nested loop")
}

fun testLabel1() {
    listOf(1, 2, 3, 4, 5).forEach {
        if (it == 3) return // ⾮局部直接返回到 foo() 的调⽤者 即跳出foo方法
        println(it)
    }
    println("this point is unreachable")
}

fun testLabel2() {
    listOf(1, 2, 3, 4, 5).forEach lit@{// 声明标签
        if (it == 3) return@lit //使用标签 跳到声明标签的地方
        // 局部返回到该 lambda 表达式的调⽤者, 即 forEach 循环 而不是跳出整个方法 其实类似一个continue
        // 但是break和continue都是用在循环中的关键字 标签就起到替代作用
        print(it)
    }
    println(" done with explicit label")
}

fun testLabel3() {
    listOf(1, 2, 3, 4, 5).forEach {// 省略了标签的声明
        if (it == 3) return@forEach // 局部返回到该 lambda 表达式的调⽤者, 即 forEach 循环
        // 常情况下使⽤隐式标签更⽅便。本例就是一个隐式标签 该标签与接受该 lambda 的函数同名
        print(it)
    }
    println(" done with implicit label")
}

fun testLabel4() {
    listOf(1, 2, 3, 4, 5).forEach(fun(value: Int) {// 这里使用了匿名内部类替代lambda表达式
        // 因为return效果是推出函数执行体 那么这里的return只能跳出当前函数 起到的作用和上面一样 即一个continue
        if (value == 3) return // 局部返回到匿名函数的调⽤者, 即 forEach 循环
        print(value)
    })
    print(" done with anonymous function")
}


fun classicBreakContinue() {
    for (i in 1..10) {
        if (i == 3) {
            continue // i 为 3 时跳过当前循环,继续下一次循环
        }
        println(i)
        if (i > 5) {
            break // i 为 6 时 跳出循环
        }

    }
}

fun testLabel() {
    // 声明标签
    loop@ for (i in 1..100) {
        if (i == 10) break@loop //使用标签 跳到声明标签的地方 类似但不等价于C的goto
        println(i)
    }
}

fun testReturn(string: String?) {
    println("start=====")
    // ?:是一个二元表达式 如果 参数string==null 走前面的分支
    // 否则 走后面的分支
    val s = string ?: return
    println(s)
    println("end=====")
}

class D02Basic04BreakContinue {
}