Kotlin学习 - Kotlin中的标准函数let、with、run、apply

Kotlin标准函数:

标准函数let

fun main() {
    val student = Student("lucky", 19);
    study(student)
}

fun study(student: Student?) {
    study?.doHomework()
    study?.readBooks()
}

在Kotlin学习 - 可空系统类型中,如果入参是可以为空的,那么函数中每次调用该对象函数都需要加?.,代码编写太过繁琐。这个时候就可以结合使用?.操作符和let函数来对代码进行优化了,如下所示:

fun main() {
    val student = Student("lucky", 19);
    study(student)
}

fun study(student: Student?) {
    student?.let { s ->
        s.doHomework()
        s.readBooks()
    }
}

?.操作符表示对象为空时什么都不做,对象不为空时就调用let函数。之前做lamda表达式优化的时候讲(Kotlin学习 - 集合):当Lambda 表达式的参数列表中只有一个参数时,也不必声明参数名,而是可以使用it关键字来代替,因此上面代码可以优化下:

fun main() {
    val student = Student("lucky", 19);
    study(student)
}

fun study(student: Student?) {
    student?.let {
        it.doHomework()
        it.readBooks()
    }
}

let除了可以帮我们简化非空判断,在多线程中还可以控制处理全局变量的判空问题。

var student: Student? = null

fun study() {
    if (student !=null){
        student.doHomework()
        student.readBooks()
    }
}

上面代码是会编译报错的,是因为全局变量的值随时都有可能被其他线程所修改,即使做了判空处理,仍然无法保证if语句中的student变量没有空指针风险。使用let函数修改下:

var student: Student? = null

fun study() {
    student?.let {
		it.doHomework()
		it.readBooks()
    }        
}

报错消失,判断student变量不为空后,执行let中的语句,let可确保lambda语句执行的过程中student变量一直不为空。

总结:let可以帮我们简化非空判断,在多线程中还可以控制处理全局变量的判空问题。

标准函数with

fun main() {
    val fruits = listOf("apple", "banana", "pear")
    println(fruitPrint(fruits))
}

上面有个水果列表,需求是按固定的格式拼接起来,惯常实现方法如下:

fun fruitPrint(fruits: List<String>): String {
    val fruitPrint = StringBuilder();
    fruitPrint.append("My favorite fruits are : \n")
    
    for (f in fruits) {
        fruitPrint.append(f).append("\n")
    }
    
    fruitPrint.append("----- end -----")
    return fruitPrint.toString()
}

//打印结果
My favorite fruits are : 
apple
banana
pear
----- end -----

在拼接字符串的地方连续调用了多次StringBuilder对象。针对这种场景我们可以用with函数来让代码变得更加精简。

fun fruitPrint(fruits: List<String>): String {
   return with(StringBuilder()) {
        append("My favorite fruits are : \n")
        for (f in fruits) {
            append(f).append("\n")
        }
        append("----- end -----")
        toString()
    }
}

with函数的第一个参数传入了一个StringBuilder对象,那么整个Lambda 表达式的上下文就会是这个StringBuilder对象。于是我们在Lambda 表达式可以直接调用append()toString()方法。Lambda 表达式的最后一行代码会作为with函数的返回值返回。

总结:需要同一对象频繁操作的时候,可以使用with函数精简代码。

标准函数run

run函数的用法和with函数是非常类似的,不过run函数通常不会直接调用,而是要在某个对象的基础上调用。而且with有两个入参,run只有一个Lambda表达式入参。

同样的是,withrun的Lambda 表达式中的最后一行代码作为返回值返回。

上面例子用run函数重写下:

fun fruitPrint(fruits: List<String>): String {
   return StringBuilder().run {
        append("My favorite fruits are : \n")
        for (f in fruits) {
            append(f).append("\n")
        }
        append("----- end -----")
        toString()
    }
}

标准函数apply

apply函数和run函数用法类似,都要在某个对象上调用,并且只接收一个Lambda 参数,也会在Lambda 表达式中提供调用对象的上下文,但是apply函数无法指定返回值,而是会自动返回调用对象本身。

fun fruitPrint(fruits: List<String>): String {
     val sb = StringBuilder().apply {
        append("My favorite fruits are : \n")
        for (f in fruits) {
            append(f).append("\n")
        }
        append("----- end -----")       
    }
    return sb.toString()
}

由于apply函数无法指定返回值,只能返回调用对象本身,因此无法直接返回,我们的返回值声明的是String类型,因此还需要转化下。

你可能感兴趣的:(kotlin,kotlin,android,学习)