Kotlin学习笔记 —— 函数,字符串,可空性以及标准库函数(2)

函数

1.1 函数的定义

  1. fun定义函数的关键字
  2. 参数声明格式为"参数名:参数类型"
  3. Kotlin函数语法糖:函数**只有一行代码时可以不写函数体!直接用等号连接在函数定义的尾部**
fun largeNumber(num1:Int,num2:Int) = max(num1,num2)
fun 函数名(参数列表): 返回值类型{
函数内容
return 返回值
}
private fun doSomething (age:Int, flag:Boolean):String
可见性修饰符 函数声明关键字 函数名 函数参数 返回类型
fun main() {
    println(doSomething(5, false))
}
//声明函数 默认修饰符是public
private fun doSomething(age:Int, flag:Boolean):String{
    return "result"
}

1.2 函数参数

默认值参 如果不打算传入值参 可以预先给参数指定默认值、

优点:避免创建重载的函数

fun main() {
    fix("scout", 3)     //age为缺损值 不传的话用默认值
}

//定义缺损值的时候必须在后面 public定义函数时可以去掉 默认就是public
//函数没有返回值时后面可以不跟东西
fun fix(name: String, age: Int = 2){
    println(name + age)
}

具名函数参数 如果使用命名值参 就可以不用管值参的顺序

fun main() {
    fix(age = 10, name = "jiejie")      //具名的函数参数传参时可以不用管顺序 但是一定要指名
}
//定义缺损值的时候必须在后面 public定义函数时可以去掉 默认就是public
//函数没有返回值时后面可以不跟东西
fun fix(name: String, age: Int = 2){
    println(name + age)
}

1.3 Unit函数

在Kotlin中,针对不需要返回具体数据的函数,我们可以声明返回类型为Unit。就如同java中没有数据返回的函数声明为void一样。

而针对Unit函数,我们通常情况下是可以省略掉的。我们如果不定义的话,kotlin会自动编译为Unit。

我们可以默认省略掉Unit 和函数中的return。所以,在Kotlin中unit代表的就是没有实际意义的数据。

Kotlin中没有返回值的函数叫Unit函数,也就是说返回类型是Unit

在Kotlin之前没有返回值的函数用void表示 意思是没有返回类型 也就是说如果函数不返回任何东西 就忽略类型 但是这种解决方案无法解释泛型

fun main() {
    println(fix("scout", 3))    //kotlin.Unit
}

fun fix(name: String, age: Int = 2){
    println(name + age)
}

1.4 Nothing函数

在Kotlin中有一个特殊的数据类型Nothing。它只能用于函数返回类型声明,不能定义为变量声明。相较于而言,Unit可以定义为变量声明。Nothing声明的函数永远不会返回正常值,只会抛出异常。

通常在单元测试框架执行测试失败的时候,可以通过定义Nothing返回类型的函数来抛出异常。

我们如果进行sdk开发,在用户使用时没有按照规范调用时我们也可以定义检测函数,并使用Nothing返回类型来抛出异常终止程序运行等。

Kotlin中内置TODO函数, 该函数的任务就是抛出异常 就是永远别指望它运行成功,返回Nothing类型

fun main() {
    TODO("nothing")
    println("aaa")
}

在这里插入图片描述
TODO函数

@kotlin.internal.InlineOnly
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")

1.5 反引号中的函数名

kotlin可以使用空格和特殊字符对函数命名,不过函数名要用一对反引号括起来。

为了支持Kotlin和Java互操作,而Kotlin和java各自却有着不同的保留关键字,不能作为函数名,使用反引号括住函数名就能避免任何冲突

fun main() {
    MyJava.`is`()       //is在Kotlin中是关键字 可以用反引号引起来避免冲突
}
fun `**~special function with weird name~**`(){

}
public class MyJava {
    public static void is() {
        System.out.println("is");
    }
}

1.6 匿名函数

定义时不取名字的函数,匿名函数通常整体传递给其他函数,或者从其他函数返回。

匿名函数对Kotlin来说很重要,有了它,我们就能根据需要制定特殊的规则,轻松定制标准库里的内置函数

fun main() {
    //使用匿名函数给标准函数制定规则
    val total = "Mississippi".count()
    //第一个letter是变量 下一行是函数体
    val totalS = "Mississippi".count({ letter ->
        letter == 's'
    })
    println(total)
    println(totalS)
}
//第二种
fun main() {
    //使用匿名函数给标准函数制定规则
    val total = "Mississippi".count()
    //第一个letter是变量 下一行是函数体
    val totalS = "Mississippi".count {
        it == 's'
    }
    println(total)
    println(totalS)
}
//第三种
fun main() {
    //使用匿名函数给标准函数制定规则
    val total = "Mississippi".count()
    //第一个letter是变量 下一行是函数体
    val totalS = "Mississippi".count{ letter ->
        letter == 's'
    }
    println(total)
    println(totalS)
}

1.7 函数类型与隐式返回

匿名函数也有类型,可以当作变量赋值给函数类型的变量,就像其他变量一样。匿名函数就可以在代码里传递了。变量有类型,变量可以等于函数,函数也有类型。函数的类型,由传入的参数和返回值类型决定

和具名函数不同,除了极少数情况外,匿名函数不需要return关键字来返回数据,匿名函数会隐式或自动返回函数体最后一行语句的结果。

    //变量的类型是一个匿名函数 无参 返回字符串类型的匿名函数
    val blessingFunction: () -> String = {
        val holiday = "New Year."
        "Happy $holiday"
        //一般情况下把最后一句代码返回
    }
    println(blessingFunction)   //() -> kotlin.String
    println(blessingFunction())     //Happy New Year.

1.8 函数参数

和具名函数一样,匿名函数可以不带参数,也可以带一个或多个任何类型的参数,需要带参数时,参数的类型放在匿名函数的类型定义中,参数名则放在函数定义中

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UY3xA1ay-1653651816409)(C:\Users\judicious\AppData\Roaming\Typora\typora-user-images\image-20220519220508163.png)]

    val blessingFunction2:(String) -> String = { name ->	//name为传入的参数
        val holiday = "New Year."
        "$name and $holiday"
        //一般情况下把最后一句代码返回
    }

    println(blessingFunction2("scout"))  //scout and New Year.

1.9 it关键字

定义只有一个参数的匿名函数时,可以使用it关键字来表示参数名。当你需要传入两个值参,it关键字就不能用啦

//it关键字
val blessingFunction3:(String) -> String = {
    val holiday = "New Year."
    "$it and $holiday"
    //一般情况下把最后一句代码返回
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ap4w4xyI-1653651827227)(C:\Users\judicious\AppData\Roaming\Typora\typora-user-images\image-20220519221923059.png)

1.10 类型推断

定义一个变量时,如果已把匿名函数作为变量赋值给它,就不需要显示指明变量类型了。

    //类型推断 不是代码块 是匿名函数  推断返回值类型
    val blessingFunction4 = {
        val holiday = "New Year."
        " and $holiday"
        //一般情况下把最后一句代码返回
    }

类型推断也支持带参数的匿名函数,匿名函数的参数名和参数类型必须有

使用类型推断以及不使用的区别

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-oqNRmFLl-1653651851391)(C:\Users\judicious\AppData\Roaming\Typora\typora-user-images\image-20220519222807244.png)]

//不使用类型推断 
val blessingFunc:(String, Int) -> String = {name, year ->
    val holiday = "New Year"
    "$name ,Happy $holiday $year"
}

//使用类型推断时  需要在传参的时候标清参数类型  参数类型推断
val blessingFunc1 = {name:String, year:Int ->
    val holiday = "New Year"
    "$name ,Happy $holiday $year"
}

1.11 lambda

将匿名函数称为lambda,将它的定义称为lambda表达式,它返回的数据称为lambda结果

1.12 定义参数是函数的函数

函数的参数是另一个函数

//定义一个函数是另一个函数的参数
fun main() {
    val getWords = {goodName:String,  hour:Int ->
        val currentYear = 2002
        "$currentYear 年"  //中间有空格 没有空格就会将后面的字符当作变量名
        "${currentYear}年, ${goodName} ${hour}"  //带括号后可以不用空格
    }

    showOnBoard("xxx", getWords)
}

//具名函数
fun showOnBoard(goodName: String, getWords:(String, Int) -> String) {
    val hour:Int = (1..24).shuffled().last()
    println(getWords(goodName, hour))

}

简略写法

如果一个函数的lambda参数排在最后,或者是唯一的参数,那么括住lambda值参的一对圆括号就可以省略。

val total = "Mississippi".count({ it == 's' })
val totalS = "Mississippi".count { it == 's' }
//定义一个函数是另一个函数的参数
fun main() {
    val getWords = {goodName:String,  hour:Int ->
        val currentYear = 2002
        "$currentYear 年"  //中间有空格 没有空格就会将后面的字符当作变量名
        "${currentYear}年, ${goodName} ${hour}"  //带括号后可以不用空格
    }

    showOnBoard("xxx", getWords)
}

//具名函数
fun showOnBoard(goodName: String, getWords:(String, Int) -> String) {
    val hour:Int = (1..24).shuffled().last()
    println(getWords(goodName, hour))

}


//简略后
//定义一个函数是另一个函数的参数
fun main() {
    showOnBoard("xxx") { goodName: String, hour: Int ->
        val currentYear = 2002
        "$currentYear 年"  //中间有空格 没有空格就会将后面的字符当作变量名
        "${currentYear}年, $goodName $hour"  //带括号后可以不用空格
    }

}

//具名函数
private fun showOnBoard(goodName: String, getWords:(String, Int) -> String) {
    val hour:Int = (1..24).shuffled().last()
    println(getWords(goodName, hour))

}

1.13 函数内联

lambda可以让你更灵活地编写应用 但是需要付出一定代价

在JVM上,定义的lambda会以对象实例的形式存在,JVM会为所有同lambda打交道的变量分配内存,这就产生了内存开销。lambda的内存开销会带来严重的性能问题。但是,Kotlin有一种优化机制叫做内联,有了内联,JVM就不需要使用lambda对象实例了,因而避免了变量内存分配。哪里需要使用lambda,编译器就会将函数体复制粘贴到哪里

使用lambda的递归函数无法内联,因为会导致复制粘贴无限循环,编译会发出警告。

1.14 函数引用

要把函数作为参数传给其他函数使用,除了传lambda表达式,kotlin还提供了其他方法,传递函数引用,函数引用可以把一个具名函数转换成一个值参,使用lambda表达式的地方,都可以使用函数引用。

fun main() {
    //要获得函数引用,使用::操作符,后跟要引用的函数名
    showOnBoard("viper", ::getDiscountWords)
}

private fun getDiscountWords(goodName: String, hour:Int):String {
    val currentYear = 2002
    return "${currentYear}年, $goodName $hour"
}
//具名函数
private fun showOnBoard(goodName: String, getDiscountWords: (String, Int) -> String) {
    val hour:Int = (1..24).shuffled().last()
    println(getDiscountWords(goodName, hour))
}

1.15 函数类型作为返回类型

函数类型也是有效的返回类型,也就是说可以定义一个能返回函数的函数

fun main() {
    val getdiscountWords = configDiscountWords()
    println(getdiscountWords("viper"))
}

fun configDiscountWords(): (String) -> String {
    val currentYear = 2002
    val hour:Int = (1..24).shuffled().last()
    return { goodName:String ->
        "${currentYear}年, $goodName $hour"
    }
}

1.16 闭包

在Kotlin中,匿名函数能修改并引用定义在自己的作用域之外的变量,匿名函数引用着定义自身的函数里的变量,Kotlin中的lambda就是闭包。

作用域重复问题 根据模块分??

能够接收函数或者返回函数的函数叫做高级函数,高级函数广泛应用于函数式编程当中

1.17 lambda与匿名内部类

函数类型能让开发者少写模式化代码,写出更灵活的代码。Java 8支持面向对象编程和lambda表达式,但不支持将函数作为参数传给另一个函数或变量,不过java的替代方案是**匿名内部类。

通过匿名内部类将函数作为参数传给另一个函数或变量

import java.util.Random;

public class JavaAnonymousClass {
    public static void main(String[] args) {
        //这里匿名内部类可以调用函数参数??
        
        show("jiejie", new discountWords() {
            int a = 2;
            @Override
            public String getDiscountWords(String goodsName, int hour) {
                int currentYear = 2002;
                return String.format(String.format("%d年, %s,%d", currentYear, goodsName, a));
            }
        });
    }

    public interface discountWords{
        String getDiscountWords(String goodsName,int hour);
    }

    public static void show(String goodsName, discountWords discountWords) {
        int hour = new Random().nextInt(24);
        System.out.println(discountWords.getDiscountWords(goodsName, hour));
    }
}

null

Kotlin是编译型语言,它更多地把运行时可能出现的null问题,以编译时错误的方式,提前在编译期强迫我们重视起来,而不是等到运行时报错,防患于未然,提高了我们程序的健壮性。

可空性

对于null值问题,Koltin反其道而行之,除非另有规定,变量不可为null值,这样一来,运行时崩溃从根源上得到解决。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fc6yOQTo-1653653563290)(C:\Users\judicious\AppData\Roaming\Typora\typora-user-images\image-20220521194238609.png)]

不能直接赋值为空,除非声明

Kotlin的null类型

为了避免NullPointerException,Kotlin的做法是不让我们给非空类型变量赋null值,但null在Kotlin中依然存在。

fun main() {
    var str:String? = "scout"       //可空字符串类型
    str = null
}

null安全

Koltin区分可空类型和非可空类型,所以,你要一个可空类型变量运行,而它又可能不存在,对于这种潜在的危险,编译器时刻警惕着。为了应对这种风险,Kotlin不允许你在可空类型值上调用函数,除非你主动接手安全管理。

1. 安全调用操作符(相当于调用前 if 判空)

编译器看到有安全调用操作符,所以它知道如何检查null值。如果遇到null值,就会跳过函数调用,而不是返回null

fun main() {
    var str:String? = "scout"       //可空字符串类型
    str = null
    str?.capitalize()  //?.安全调用操作符 当str为空时自动跳过这个函数
    println(str)
}
使用带let的安全调用

安全调用允许在可空类型上调用函数,但是如果还想做点额外的事,比如创建新值,或判断不为null就调用其他函数,怎么办?

可使用带let函数的安全调用操作符。可以在任何类型上调用let函数,它的主要作用是让你在指定的作用域内定义一个或多个变量。

fun main() {
    var str:String? = "scout"       //可空字符串类型
    str = null
    //不为空才会调用后面的let函数 为空不调用
    str = str?.let {
        //非空白字符串
        if(it.isNotBlank()) {
            it.capitalize()
        }else {
            "scout"
        }
    }
    println(str)
}

2. 使用非空断言操作符

!!又称感叹号操作符,当变量值为null时,会抛出KotlinNullPointerException

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iJEHfbe2-1653653597200)(C:\Users\judicious\AppData\Roaming\Typora\typora-user-images\image-20220521200857239.png)]

//可空性
fun main() {
    var str:String? = "scout"       //可空字符串类型
    str = null
    //使用非空断言操作符 当str为空时 会抛出异常
    str = str!!.capitalize()

    println(str)
}

3. 使用 if 判断 null 值情况

也可以使用if判断 但是相比之下安全调用操作符用起来更灵活,代码也更简洁,我们可以使用安全操作符进行多个函数的链式调用

    //if判断
    if(str != null) {
        str.capitalize()
    }else {
        print("为空")
    }
    //使用安全操作符链式调用
    str?.capitalize().plus("is good")

使用空合并操作符(相当于简略版三元表达式)

?:操作符:如果左边的求值结果为null,就使用右边的结果值

    //空合并操作符 ?: 如果左边为空 输出右边的值 如果不为空 输出str
    println(str ?: "viper")

空合并操作符也可以和let函数一起使用来代替if/else语句

    //可以和let函数一起使用来代替if/else语句
    str = str?.let { it.capitalize() } ?: "viper"

异常

//异常
import java.lang.IllegalArgumentException

fun main() {
    var num: Int? = null

    //处理异常
    try {
        checkOperation(num)
        num!!.plus(1)
    }catch (e : Exception) {
        println(e)
    }

}
//抛出异常
fun checkOperation(num: Int?) {
    num ?: throw UnskilledException()
}

//自定义异常
class UnskilledException() : IllegalArgumentException("操作不当")

先决条件函数

Kotlin标准库提供了一些便利函数,使用这些内置函数,可以抛出自定义信息的异常,这些便利函数叫做先决条件函数,你可以用它定义先决条件,条件必须满足,目标代码才能执行。

函数描述
checkNotNull如果参数为null,则抛出lllegalStateException异常,否则返回非null值
require如果参数为false,则抛出lllegalArgumentException异常
requireNotNull如果参数为null,则抛出lllegalStateException异常,否则返回非null值
error如果参数为null,则抛出lllegalStateException异常并输出错误信息,否则返回非null值
assert如果参数为false,则抛出AssertError异常,并打上断言编译器标记

字符串

substring

字符串截取,substring函数支持IntRange类型(表示一个整数范围的类型)的参数,until创建的范围不包括上限值

const val NAME = "Jimmy's friend"

fun main() {
    val index:Int = NAME.indexOf('\'')
    val str:String = NAME.substring(0, index)
    val str1:String = NAME.substring(0 until index)		//IntRange
    println(str)
    println(str1)
}

split

split函数返回的是List集合数据,List集合又支持解构语法特性,它允许你在一个表达式里给多个变量赋值,解构常用来简化变量的赋值。

    //根据传入参数进行拆分字符串 返回List集合
    val data:List<String> = NAMES.split(",")
    //解构语法
    val (orgin: String, dest:String, proxy:String) = NAMES.split(",")
    println("$orgin, $dest, $proxy")
    println(data[0])

replace

字符串替换

    //replace 替换字符
    val str2 = "The people's Republic of China."
    val str3 = str2.replace(Regex("[aeiou]")) {
        when(it.value) {
            "a" -> "8"
            "e" -> "6"
            "i" -> "9"
            "o" -> "1"
            "u" -> "3"
            else -> it.value
        }
    }

    println(str2)
    println(str3)

字符串的比较

在Kotlin中,用检查两个字符串中的字符是否匹配,用=检查两个变量是否指向内存堆上同一对象(常量池),而在Java中==做引用比较,做结构比较的时候用equals方法。

字符串是不可变的!!

“Jason"和"jason”.capitalize()指向不同!!

    val str1 = "Jason"
    val str2 = "jason".capitalize()
    val str3 = "Jason"
    val str4 = "jason".capitalize()
    println(str1 == str2)       //比较字符是否相等  ture
    println(str1 === str2)      //比较是否指向内存堆上同一个对象  false
    println(str1 === str3)      //true
    println(str2 === str4)      //false  字符串操作时每次都会重新创建一个对象

forEach

字符串遍历

    //字符串遍历
    "The people's Republic of China.".forEach {
        println("$it")
    }

数字类型

和java一样,Kotlin中所有数字类型都是有符号的,也就是说既可以表示正数,也可以表示负数

类型最大值最小值
Byte8127-128
Short1632767-32768
Int322147483647-2147483648
Long649223372036854775807-9223372036854775808
Float323.4028235E381.4E-45
Double641.7976931348623157E3084.9E-324

安全转换函数

Kotlin提供了toDoubleOrNull和toIntOrNull这样的安全转换函数,如果数值不能正确转换,与其触发异常不如返回null值

    //val num2:Int = "8.98".toInt()  //会抛出异常 NumberFormatException 没法将string转成int

    val num1:Int? = "8.98".toIntOrNull()        //返回null 没有转成功返回空
    println(num1)

Double转Int

    //double转int
    println(8.956789.toInt())       //double转int会丢失小数点后 精度损失  8
    println(8.956789.roundToInt())      //四舍五入转int  9

Double类型格式化(返回值是string 且会四舍五入)

    //double类型格式化
    println("%.2f".format(8.9866))      //返回的是字符串 且会四舍五入 8.99

标准库函数

apply

可看作一个配置函数,可以传入一个接收者,然后调用一系列函数来配置它以便使用,如果提供lambda给apply函数执行,它会返回配置好的接收者

    val file1 = File("C:\\Users\\judicious\\Desktop")
    file1.setReadable(true)
    file1.setWritable(true)
    file1.setExecutable(false)

    //apply函数 配置接收者对象 apply中的this和接收者对象是同一个对象 
    val file2 = File("C:\\Users\\judicious\\Desktop").apply {
        setExecutable(true)
        setWritable(true)
        setReadable(true)
    }

可以看到,调用一个个函数类配置接收者时,变量名就省掉了,这是因为,在lambda中,apply能让每个配置函数都作用于接收者,这种行为有时又叫做相关作用域,因为lambda表达式里的所有函数调用都是针对接收者的,或者说,它们是针对接收者的隐式调用。

let

let函数能使某个变量作用于其lambda表达式内,让it关键字能引用它。let与apply比较,let会把接收者传给lambda,而apply什么都不传,匿名函数执行完,apply会返回当前接收者,而let会返回lambda的最后一行

//let
fun main() {
    val result = listOf(3,2,1).first().let {
        it * it
    }
    println(result)  //9
    println(format("viper"))
}

//链式调用风格
fun format(guestName:String?):String{
    return guestName?.let {
        "welcomt, $it"      //let返回最后一行
    }?:"What's your name"
}

run

光看作用域行为,和apply差不多,但与apply不同,run函数不返回接收者,run返回的是lambda结果

import java.io.File
//run函数
fun main() {
    val file = File("C:\\Users\\judicious\\Desktop")
    val result = file.run {
        readText().contains("a")      //超过2GB不会加载 查看文件内是否包含a
    }
    println(result)
}

也能用来执行函数引用 ::

//run函数
fun main() {
    //::函数引用 返回的是最后一行
    val result1 = "capper viper scout".run(::isLong)
    println(result1)

    "capper viper scout"
        .run(::isLong)
        .run(::showMessage)
        .run(::println)
}

fun isLong(name:String) = name.length >= 10

fun showMessage(isLong: Boolean):String {
    return if(isLong) {
        "NAME IS LONG"
    }else {
        "PLEASE RENAME"
    }
}

with

with函数是run的变体,它们的功能行为是一样的,但with的调用方式不同,调用with时需要值参作为第一个参数传入

//with函数
fun main() {
    //run和with比较 只是传参方式不同
    val result1 = "The people's Republic of China".run { 
        length >= 10
    }
    val result2 = with("The people's Republic of China"){
        length >= 10
    }
}

also

also函数和let函数功能类似,和let一样,also也是把接收者作为值参传给lambda,但有一点不同:also返回接收者对象,而let返回lambda结果。所以,also尤其适合针对同一原始对象,利用副作用做事,既然also返回的是接收者对象,就可以基于原始接收者对象执行额外的链式调用。

可以不用临时变量就交换两个变量的值

import java.io.File
//also
fun main() {
    //可以链式调用 和let的区别 also返回接收者对象 let返回lambda表达式结果
    val fileContents: List<String>
    val file = File("C:\\Users\\judicious\\Desktop\\1.txt")
        .also {
            println(it.name)
        }.also {
            fileContents = it.readLines()
        }

    println(fileContents)
}

takeIf

和其他标准函数有点不一样,takeIf需要判断lambda中提供的条件表达式,给出true或false结果,如果判断结果是true,从takeIf函数返回接收者对象,如果是false,则返回null。

如果需要判断某个条件是否满足,再决定是否可以赋值变量或执行某些任务,akeIf就很有用,概念上讲,takeIf函数类似于if语句,但它的优势是可以直接在对象实例上调用,避免了临时变量赋值的麻烦。

import java.io.File
//takeIf
fun main() {
    //如果takeIf返回true就返回接收者对象 如果为false 返回null
    val result = File("C:\\Users\\judicious\\Desktop\\1.txt")
        .takeIf { it.exists() && it.canRead() }
        ?.readText()
    
    println(result)
}

takeUnless

takeIf的辅助函数takeUnless,只有判断你给定的条件结果是false时,takeUnless才会返回原始接收者对象。为true时,返回null,和takeIf相反。

import java.io.File
//takeUnless 结果false时 才会返回原始接收对象
fun main() {
    val result = File("C:\\Users\\judicious\\Desktop\\1.txt")
        .takeUnless { it.isHidden }
        ?.readText()

    println(result)
}

函数区别

let和apply let会把接收者传给let 而apply什么都不传 apply——this let——it 返回值也不同 apply返回配置好的接收者 let返回lambda的最后一行

let和run let——it run——this

run和apply run返回lambda的最后一行 apply返回配置好的接收者

also和let also返回接收者对象 let返回lambda的最后一行

also和apply also——it apply——this

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值