Kotlin基础 — 操作符:run、with、let、also、apply、takeIf、takeUnless、repeat

Kotlin基础 — 操作符:run、with、let、also、apply、takeIf、takeUnless、repeat - Elson的博客 - CSDN博客
https://blog.csdn.net/Love667767/article/details/79376813

概述
分析Kotlin的 Standard.kt 代码,主要分为三部分: 
1. run、with、let、also、apply 的比较 
2. takeIf、takeUnless、repeat 的使用 
3. 异常类的使用

一、run、with、let、also、apply 的比较
所有的总结都源自于代码,所以最终还是要回到代码中找到答案。

示例
1. run()
/**
 * Calls the specified function [block] and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R = block()


两种写法:T.run({...}) 和 T.run {},第二种写法是第一种的变种,当方法的最后一个参数是lambda表达式时,可以将表达式移出;

class Main {

    fun test(){
        // 第一种写法
        val run1 = run({
            Log.d("Main", "我是内部的Run")
            "Run1"
        })
        Log.d("Main", "我是内部的Result=$run1") //我是内部的Result=Run1

        //第二种写法
        val run2 = run {
            Log.d("Main", "我是外部的Run")
            "Run2"
        }
        Log.d("Main", "我是外部的Result=$run2" ) ////我是外部的Result=Run2
    }
}


2. T.run()
/**
 * Calls the specified function [block] with `this` value as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R = block()


class Main {
    fun test(){
        val run = "ABCDEF".run {
            substring(2) //可以在内部直接调用String的方法
        }
        Log.d("Main", "T.run()的值 = $run" ) //T.run()的值 = CDEF
    }
}


3. with()
/**
 * Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()


class Main {
    fun test(){
        val with = with("ABCDEF") {
            substring(2)
        }
        Log.d("Main", "with()的值 = $with" ) //with()的值 = CDEF
    }
}


4. apply()
/**
 * Calls the specified function [block] with `this` value as its receiver and returns `this` value.
 */
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }


class Main {
    fun test(){
        val apply = "ABCDEF".apply {
            it.substring(2)
        }
        Log.d("Main", "T.apply()的值 = $apply" )//T.apply()的值 = ABCDEF,值没有被改变
    }
}


5. also()
/**
 * Calls the specified function [block] with `this` value as its argument and returns `this` value.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }


class Main {
    fun test(){
        val also = "ABCDEF".also {
            it.substring(2)
        }
        Log.d("Main", "T.also()的值 = $also" )//T.also()的值 = ABCDEF,值没有被改变
    }
}


6. let()
/**
 * Calls the specified function [block] with `this` value as its argument and returns its result.
 */
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)


class Main {
    fun test(){
        val let = "ABCDEF".let {
            it.substring(2) //这里需要使用it
        }
        Log.d("Main", "T.let()的值 = $let" ) //T.let()的值 = CDEF
    }
}


2. 结论


源码:

public inline fun <R> run(block: () -> R): R = block()
public inline fun <T, R> T.run(block: T.() -> R): R = block()
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)


从三个维度去分析: 
1. 该操作符是被某个类的对象调用,还是直接调用(即:run() 还是 T.run() )。 
2. 对象T是否被当做参数(即:T.also() 、T.let())。 
3. 返回值是否是return this(即:T.apply()、T.also())。

操作符    接收者(this)    参数(it)    返回值(result)    典型应用场景
run ( block: () -> R ) : R    当前类    /    类R(最后一行)    
T.run ( block: T.() -> R ) : R    类T    /    类R(最后一行)    
with ( receiver: T, block: T.() -> R ) : R    类T    /    类R(最后一行)    
T.apply ( block: T.() -> Unit ) : T    类T    /    类T    
T.also ( block: (T) -> Unit ) : T    当前类    类T    类T    
T.let ( block: (T) -> R ) : R    当前类    类T    类R(最后一行)    
分析:
run() 和 T.run() 比较: 
T.run() 的参数T.()表示在其block中可以直接使用T的所有public方法,而run() 却不行;
T.apply()、T.also() 和 其他几个比较:

返回值都是return this,所以返回的都是之前的对象T ;
由于 T.also() 方法体中有 block(this),将 this 作为参数传入,所以在Lambda类型的block内部就不能再用this 获取当前的传入参数T,而要使用it 获取T,而this 实际代表的是当前所处的类;
T.also()、T.let() 和 其他几个比较: 
这两个方法都将T作为参数传入,且方法体中都将 this 传入 block(this),所以T必须都要用it来获取;


二、takeIf、takeUnless、repeat 的使用
源码
/**
 * Returns `this` value if it satisfies the given [predicate] or `null`, if it doesn't.
 * 
 * 根据当前predicate的返回值判断:若为空,则返回null,若不为空,则返回原值
 * 根据上面的总结,在predicate中获取传入的参数T时要使用it,而不是this;
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null

/**
 * Returns `this` value if it _does not_ satisfy the given [predicate] or `null`, if it does.
 */
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null


示例
class Main {

    fun test(){
        val takeif = "ABC".takeIf {
            Log.d("Main", "this = $this") //this = com.example.kotlindemo.Main@f17fc13
            Log.d("Main", "it = $it") //it = ABC
            true //如果是false,则返回null
        }
        Log.d("Main", "我是takeif=$takeif" ) //我是takeif=ABC
    }
}


/**
 * Executes the given function [action] specified number of [times].
 *
 * A zero-based index of current iteration is passed as a parameter to [action].
 */
@kotlin.internal.InlineOnly
public inline fun repeat(times: Int, action: (Int) -> Unit) {
    for (index in 0..times - 1) {
        action(index)
    }
}


class Main {
    fun test(){
        repeat(10) {
            Log.d("Main",  "this = $this") //this = com.example.kotlindemo.Main@f17fc13
            Log.d("Main",  "$it")
        }
    }
}


输出的值:

com.example.kotlindemo D/Main: 0 
com.example.kotlindemo D/Main: 1 
com.example.kotlindemo D/Main: 2 
com.example.kotlindemo D/Main: 3 
com.example.kotlindemo D/Main: 4 
com.example.kotlindemo D/Main: 5 
com.example.kotlindemo D/Main: 6 
com.example.kotlindemo D/Main: 7 
com.example.kotlindemo D/Main: 8 
com.example.kotlindemo D/Main: 9

三、异常类的使用
源码
public class NotImplementedError(message: String = "An operation is not implemented.") : Error(message)
public inline fun TODO(): Nothing = throw NotImplementedError()
public inline fun TODO(reason: String): Nothing = throw NotImplementedError("An operation is not implemented: $reason")


示例
//Kotlin代码
class Command {
    fun execute(){
        TODO() //抛出异常
    }
}

class Test {
    val command = Command()
    command.execute()// 当执行到这行代码时,就会抛出异常NotImplementedError
}

猜你喜欢

转载自blog.csdn.net/guyue35/article/details/86087884