优美编码kt(1)-kotlin的let、also、apply、run

858 阅读3分钟

1. Kotlin扩展函数

Kotlin扩展函数支持扩展一个类的新功能而不需要继承或者使用装饰者模式,通过扩展来实现。其本质是自动生成一个带有当前对象的函数,当在Kotlin 中调用扩展函数时,编译器将会调用自动生成的函数并且传入当前的对象。可以通过将Kotlin字节码反编译为Java进行验证,具体demo如下:

/** String扩展函数 demo */ 
fun String.say(str: String) {
  Log.e("TAG""say: $str $this")
}
/** String扩展函数demo的实现 */ 
public final class MainActivityKt {
   public static final void say(@NotNull String $receiver, @NotNull String str) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      Intrinsics.checkParameterIsNotNull(str, "str");
      Log.e("TAG""say: " + str + ' ' + $receiver);
   }
}

2. Standard中的run、apply、let和also

通过Standard源码分析,提供的以上四个扩展函数的区别如下图所示,主要可以根据扩展函数返回值参数lamada表达式的参数来进行区分。

  • 根据返回值来划分:run和let的返回值是lamada表达式的返回值,apply和also是执行扩展函数的本身对象
  • 根据扩展函数lamada表达式的形参来区分:run和apply的lamada表达式没有参数,let和also的参数是执行扩展函数的本身对象
/**
 * 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 {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    // lamada表达无式参数,返回lamada表达式结果
    return block()
}

/**
 * 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 {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    // lamada表达无式参数
    block()
    // 返回自身
    return this
}

@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
}

/**
 * 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 {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return block(this)
}

3.Standard 总结

首先根据需要的返回值选择合适的内联函数,需要返回自身对象接着进行处理就使用also和apply,但是also和apply的选择,理论上also可以实现apply的所有功能,但最好遵循最小原则,当我们不需要在lamada表达式中使用自身对象是还是选择apply。