Kotlin学习笔记(五) - Standard.kt中的常用方法(let、with、apply等等)

创建一个demo工程,使用Android Studio搜索Standard.kt文件,可以打开Kotlin为我们准备的一系列提高编程速度,增加编程便捷性的方法

1、run方法
调用不需要有主语,可直接调用,传入一个代码块,该代码块假设返回类型为R,run方法内部将直接执行代码块内容,并将代码块的返回值(R类型)直接作为run方法的返回值进行返回,注意:代码块的最后一行是返回值

// run方法
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
// a、展开写法
// 1、定义一个变量a它是一个fun类型,即a是一个函数,该函数返回值为Int类型,函数体内最后返回3
// 2、执行Kotlin提供的run方法,并将a作为参数值传入,run方法执行(内部是在执行a函数)后,将a函数执行结果(3)返回给result接收
// 3、可以理解为run方法只是一个壳

var a = fun(): Int {
    // somethings you want to do
    return 3
}
var result = run(a)
println("result=$result")

---------------------------------------------------------------------------------------------------------------------------------------
// b、简便写法
// 1、无需定义变量,无需定义函数,直接执行,一步到位

var result  = run {
    // somethings you want to do
    3
}
println("result=$result")

2、T.run方法
泛型T(任意合法类型)作为调用主语,传入参数为T类型的扩展方法(注意,Kotlin中当参数列表的最后一个参数为函数类型时,可以直接写在小括号外面的大括号里),该方法返回值类型为R,同时和上述run方法一样,T.run方法也是直接将传入的扩展方法的返回值作为自己的返回值进行返回

// T.run方法
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block()
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
// 1、创建一个类Cat,里面有speak方法
// 2、定义一个任意方法,返回值为Int类型
// 3、定义一个cat对象
// 4、让cat执行run方法,则run方法内,有一个this可供使用(this即cat.run{...}此处的cat)

class Cat {
    var name = "xiaobai"
    fun speak() {
        println("喵喵喵~")
    }
}
var otherFun = fun(): Int {
    println("我是打酱油的fun")
    return 3
}
var cat: Cat = Cat()
var result = cat.run {
    // somethings you want to do
	// there is a 'this' in this scope, so you can run cat's speak() method directly
    speak()
    name = "xiaohei"
    // somethings you want to do
    otherFun() // otherFun()'s return value will be returned as run()'s return
}
println("result=$result")

3、with方法
调用不需要有主语,可直接调用,传入一个T类型,和一个代码块(注意,Kotlin中当参数列表的最后一个参数为函数类型时,可以直接写在小括号外面的大括号里),该代码块假设返回类型为R,with方法内部将T作为调用主语去执行代码块内容,并将代码块的返回值(R类型)直接作为with方法的返回值进行返回

// with方法
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
// 1、同T.run方法,定义一个cat对象
// 2、将cat作为with的第一个参数传入
// 3、执行with方法,和T.run方法非常类似,里面也有一个this可供使用(this即传入的cat)

var cat: Cat = Cat()
var result = with(cat) {
    // somethings you want to do
	// there is a 'this' in this scope, so you can run cat's speak() method directly
    speak()
    name = "xiaohei"
    // somethings you want to do
    otherFun() // otherFun()'s return value will be returned as with()'s return
}
println("result=$result")

4、T.apply方法
泛型T类型作为调用主语,传入一个没有返回值的函数(Unit表示没有返回值类型,同Java中void),apply执行完后,返回调用主语本身

// T.apply方法
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
// 1、简单说,就是使用apply进行一系列各种骚操作,然后返回调用者本身,但是,并不是我们想象的出淤泥而不染,而是apply里对cat的各种操作都应用在了cat身上,最后apply执行完,返回那个cat对象的引用(引用当然不会变,但是cat的name已经变成了xiaohei),然后继续调用此cat的speak方法

var cat: Cat = Cat()
println("result=${cat.name}")
cat.apply {
    name = "xiaohei"
}.speak()
println("result=${cat.name}")

5、T.also方法
和apply非常像,只是将T.()改为了(T),此时scope内不再有this,而是T作为一个参数传入函数,因此变成了it(it为系统默认变量名)

// T.also方法
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block(this)
    return this
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
var cat: Cat = Cat()
cat.also {
    name = "xiaohei"// 报错
    this.name = "xiaohei"// 报错
    it.name = "xiaohei"
}.speak()

6、T.let方法
无非就是把also方法的返回值由调用主语的T类型改为了R类型(R为传入函数的返回值类型),这也很好理解,also或者apply的目的是要返回调用主语T,所以传入的函数返回值类型为什么都没有用,执行完also方法,也拿不到传入函数的返回值,所以干脆Unit类型即可,而let方法不打算返回T,而是打算返回传入函数的返回值,让程序员可以拿到传入函数的返回值进行后续操作,let的一个主要作用,就是提供了一个it可供使用(it即调用主语T对象)

@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
// 1、let内执行一些操作(这些操作可能和cat有关,也可能无关,但是一般都有关系时使用let,即操作和返回值都和调用主语相关时,使用let),然后给出一个返回值3,结束

var result = cat.let { 
    it.name = "xiaohei"
    3
}

7、T.takeIf方法
泛型T类型作为调用主语,传入一个函数,该函数返回值类型为Boolean类型,如果返回true,则takeIf方法返回调用主语本身;如果返回false,则takeIf方法返回null

@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (predicate(this)) this else null
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
var cat:Cat = Cat()
cat.name = "xiaohei"
var temp = cat.takeIf {
    it.name == "xiaohei"
}
println(temp == cat) // true
println(temp === cat) // true

var cat:Cat = Cat()
cat.name = "xiaohei"
var temp = cat.takeIf {
    it.name = "libai" // any code what you want to do
    it.name == "xiaohei" // 最后一行的执行结果是内部函数的返回值,不是takeIf的返回值,takeIf的返回值是cat或null,详见takeIf方法
}
println(temp == cat) // false,takeIf 内部对name进行了修改,故内部函数返回false(it.name == "xiaohei"这句是false),故takeIf最终返回null,此时null和cat比较肯定为false
println(temp === cat) // false,同上

8、T.takeUnless方法
和takeIf方法正好相反,内部判断条件返回false,则takeUnless返回调用主语本身,否则返回null

@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? {
    contract {
        callsInPlace(predicate, InvocationKind.EXACTLY_ONCE)
    }
    return if (!predicate(this)) this else null
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
大写的**略**

9、repeat方法
没有调用主语,传入要执行的函数块的计划执行次数,和要执行的函数

@kotlin.internal.InlineOnly
public inline fun repeat(times: Int, action: (Int) -> Unit) {
    contract { callsInPlace(action) }

    for (index in 0 until times) {
        action(index)
    }
}

// 使用示例
---------------------------------------------------------------------------------------------------------------------------------------
// 示例1

repeat(3){
    println(it) // it 是函数内默认变量,表示当前调用次数
    println("hello")
}
// 调用结果:
// 0
// hello
// 1
// hello
// 2
// hello

// 示例2

var aa = fun(ii: Int) {
    println("hello + $ii")
}
repeat(3, aa)
// 调用结果:
// hello + 0
// hello + 1
// hello + 2
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值