我正在参与「启航计划」

Kotlin是由JetBrains开发的针对JVM、Android浏览器的静态编程言语,是Android的官方言语。Kotlin拥有较多高档而又简练的语法特性,提升了咱们的开发效率,减少了代码量。

在开端之前先看一块代码段:

fun printLength(str: String? = null) {
    println(str?.length) // 1
    if (!TextUtils.isEmpty(str)) { // 2
        println(str?.length) 
    }
    if (!str.isNullOrEmpty()) {  // 3
        println(str.length)
    }
}

为何1和2两处需要增加问号?,而3处则不需要,为什么呢?直接见源码,这儿的isNullOrEmpty其实是Kotlin中Strings.kt的扩展办法:

@kotlin.internal.InlineOnly
public inline fun CharSequence?.isNullOrEmpty(): Boolean {
   contract {
     returns(false) implies (this@isNullOrEmpty != null)
   }
​
   return this == null || this.length == 0
}

你会发现里边应用了contract,咱们不妨照着用contract写一个:

@ExperimentalContracts
inline fun String?.isNotNullWithContract(): Boolean {
    contract {
        returns(true) implies (this@isNotNullWithContract != null)
    }
​
    return this != null && this.isNotEmpty()
}

那咱们运用一下看看:

class CheckNullTest {
   @ExperimentalContracts
   inline fun String?.isNotNullWithContract(): Boolean {
     contract {
       returns(true) implies (this@isNotNullWithContract != null)
     }
​
     return this != null && this.isNotEmpty()
   }
​
   @ExperimentalContracts
   fun printLength(str: String? = null) {
     println(str?.length) // 1if (!TextUtils.isEmpty(str)) { // 2
       println(str?.length)
     }
​
     if (!str.isNullOrEmpty()) {  // 3
       println(str.length)
     }
​
     if (str.isNotNullWithContract()) {  // 4
       println(str?.length)
     }
   }
}

你会发现4处仍是需要用问号?,怎样仿着写无效,contract没有生效?看contract源码:

/**
 * Specifies the contract of a function.
 *
 * The contract description must be at the beginning of a function and have at least one effect.
 *
 * Only the top-level functions can have a contract for now.
 *
 * @param builder the lambda where the contract of a function is described with the help of the [ContractBuilder] members.
 *
 */
@ContractsDsl
@ExperimentalContracts
@InlineOnly
@SinceKotlin("1.3")
@Suppress("UNUSED_PARAMETER")
public inline fun contract(builder: ContractBuilder.() -> Unit) { }
​

见注释中Contracts are allowed only for top-level functions, 原来是运用的姿态有问题,那换个姿态再来一次:

@ExperimentalContracts
inline fun String?.isNotNullWithContract(): Boolean {
   contract {
     returns(true) implies (this@isNotNullWithContract != null)
   }
​
   return this != null && this.isNotEmpty()
}
​
class CheckNullTest {
​
   @ExperimentalContracts
   fun printLength(str: String? = null) {
     println(str?.length) // 1if (!TextUtils.isEmpty(str)) { // 2
       println(str?.length)
     }
​
     if (!str.isNullOrEmpty()) {  // 3
       println(str.length)
     }
​
     if (str.isNotNullWithContract()) {  // 4
       println(str.length)
     }
   }
}

此刻发现终于和Kotlin中Strings.kt的扩展办法isNullOrEmpty()表现一致了,不用增加问号?了。

contract(契约)是一种 Kotlin 面向编译器约定的一种规矩,它帮助编译器更加智能地识别某些需要特定的代码条件,为代码创建更加友爱的上下文关联环境。 Kotlin 在 1.3 版本以实验室功能的方式开端引进 contract, 截止至当前 Kotlin 最新版本 1.6.10,contract 办法仍然增加有 @ExperimentalContracts 注解。

常见标准库函数run,also,with,apply,let,每个里边都用到contract契约:

//以apply函数举例,其他函数同理
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
   contract {
     callsInPlace(block, InvocationKind.EXACTLY_ONCE)
   }
   block()
   return this
}