/**scope function:为对象提供一个临时局部范围内的函数，以使代码更简洁易读
1）传入参数方式分：代表context object自身
this:run, with，apply
it: also,let
2）按返回值分：
Lambda result： run,with，let
context object：also,apply，
 */
fun main(vararg arg: String) {
    //let:常用于链式调用,用于非空对象
    println("-----------------let------------------")
    val numbers = mutableListOf("one", "two", "three", "four", "five")
    numbers.map { it.length }.filter { it > 3 }.let { println(it) }
    numbers.map { it.length }.filter { it > 3 }.let(::println)
    val str: String? = "Hello"
    //processNonNullString(str)       // compilation error: str can be null
    val length = str?.let {
        println("let() called on $it")
        //processNonNullString(it)        // OK: 'it' is not null inside '?.let { }'
        it.length
    }
    println("str legth is: $length")

    //with:建议使用时不带lambda返回值，group函数调用，with this object, do the following
    println("-----------------with------------------")
    with(numbers) {
        println("'with' is called with argument $this")
        println("It contains $size elements")
    }
    var firstAndLast = with(numbers) {
        "The first element is ${first()}," +
                " the last element is ${last()}"
    }
    println(firstAndLast)

    //run:与with功能完全相同，但调用方式不同（调用方式与let相同），用于对象配置和计算结果
    println("-----------------run------------------")
    numbers.run {
        println("'run' is called with argument $this")
        println("It contains $size elements")
    }
    firstAndLast = numbers.run {
        "The first element is ${first()}," +
                " the last element is ${last()}"
    }
    println(firstAndLast)

    val hexNumberRegex = run {
        val digits = "0-9"
        val hexDigits = "A-Fa-f"
        val sign = "+-"
        Regex("[$sign]?[$digits$hexDigits]+")
    }

    for (match in hexNumberRegex.findAll("+1234 -FFFF not-a-number")) {
        println(match.value)
    }

    //apply:常用于对象配置，可链式调用，apply the following assignments to the object
    println("-----------------apply------------------")
    val adam = Person("Adam").apply {
        age = 32
        city = "London"
    }
    println("age=$adam.age,city=$adam.city")

    //also:also do the following with the object
    println("-----------------also------------------")
    numbers
        .also { println("The list elements before adding new one: $it") }
        .add("six")
    println(numbers)
}

data class Person(var name:String){
    var age:Int=0
    var city:String=""
}
