首页 文章

Kotlin中有多个变量

提问于
浏览
54

有没有办法在kotlin中为多个可变变量链接多个let?

fun example(first: String?, second: String?) {
    first?.let {
        second?.let {
            // Do something just if both are != null
        }
    }
}

我的意思是,像这样:

fun example(first: String?, second: String?) {
    first?.let && second?.let { 
        // Do something just if both are != null
    }
}

5 回答

  • 9

    以下是一些变体,具体取决于您要使用的样式,如果您拥有相同或不同类型的所有内容,以及列表未知数量的项目...

    混合类型,全部不能为null以计算新值

    对于混合类型,您可以为每个参数计数构建一系列函数,这些函数可能看起来很傻,但对于混合类型可以很好地工作:

    fun <T1: Any, T2: Any, R: Any> safeLet(p1: T1?, p2: T2?, block: (T1, T2)->R?): R? {
        return if (p1 != null && p2 != null) block(p1, p2) else null
    }
    fun <T1: Any, T2: Any, T3: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, block: (T1, T2, T3)->R?): R? {
        return if (p1 != null && p2 != null && p3 != null) block(p1, p2, p3) else null
    }
    fun <T1: Any, T2: Any, T3: Any, T4: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, p4: T4?, block: (T1, T2, T3, T4)->R?): R? {
        return if (p1 != null && p2 != null && p3 != null && p4 != null) block(p1, p2, p3, p4) else null
    }
    fun <T1: Any, T2: Any, T3: Any, T4: Any, T5: Any, R: Any> safeLet(p1: T1?, p2: T2?, p3: T3?, p4: T4?, p5: T5?, block: (T1, T2, T3, T4, T5)->R?): R? {
        return if (p1 != null && p2 != null && p3 != null && p4 != null && p5 != null) block(p1, p2, p3, p4, p5) else null
    }
    // ...keep going up to the parameter count you care about
    

    用法示例:

    val risk = safeLet(person.name, person.age) { name, age ->
      // do something
    }
    

    当list没有空项时执行代码块

    这里有两种风格,第一种是当列表包含所有非空项时执行代码块,第二种是在列表至少有一个非空项时执行相同的代码 . 两种情况都会将非空项列表传递给代码块:

    功能:

    fun <T: Any, R: Any> Collection<T?>.whenAllNotNull(block: (List<T>)->R) {
        if (this.all { it != null }) {
            block(this.filterNotNull()) // or do unsafe cast to non null collectino
        }
    }
    
    fun <T: Any, R: Any> Collection<T?>.whenAnyNotNull(block: (List<T>)->R) {
        if (this.any { it != null }) {
            block(this.filterNotNull())
        }
    }
    

    用法示例:

    listOf("something", "else", "matters").whenAllNotNull {
        println(it.joinToString(" "))
    } // output "something else matters"
    
    listOf("something", null, "matters").whenAllNotNull {
        println(it.joinToString(" "))
    } // no output
    
    listOf("something", null, "matters").whenAnyNotNull {
        println(it.joinToString(" "))
    } // output "something matters"
    

    稍微更改一下,让函数接收项目列表并执行相同的操作:

    fun <T: Any, R: Any> whenAllNotNull(vararg options: T?, block: (List<T>)->R) {
        if (options.all { it != null }) {
            block(options.filterNotNull()) // or do unsafe cast to non null collection
        }
    }
    
    fun <T: Any, R: Any> whenAnyNotNull(vararg options: T?, block: (List<T>)->R) {
        if (options.any { it != null }) {
            block(options.filterNotNull())
        }
    }
    

    用法示例:

    whenAllNotNull("something", "else", "matters") {
        println(it.joinToString(" "))
    } // output "something else matters"
    

    可以将这些变体更改为具有 let() 之类的返回值 .

    使用第一个非空项(Coalesce)

    与SQL Coalesce函数类似,返回第一个非null项 . 两种口味的功能:

    fun <T: Any> coalesce(vararg options: T?): T? = options.firstOrNull { it != null }
    fun <T: Any> Collection<T?>.coalesce(): T? = this.firstOrNull { it != null }
    

    用法示例:

    coalesce(null, "something", null, "matters")?.let {
        it.length
    } // result is 9, length of "something"
    
    listOf(null, "something", null, "matters").coalesce()?.let {
        it.length
    }  // result is 9, length of "something"
    

    其他变化

    ......还有其他变化,但更多的规格可以缩小范围 .

  • 3

    你可以为此编写自己的函数:

    fun <T, U, R> Pair<T?, U?>.biLet(body: (T, U) -> R): R? {
         val first = first
         val second = second
         if (first != null && second != null) {
             return body(first, second)
         }
         return null
     }
    
     (first to second).biLet { first, second -> 
          // body
     }
    
  • 3

    根据Kotlin的各种 *NotNull*OrNull 函数的精神,你可以创建一个 arrayOfNotNullOrNull 函数,如果所有变量都不是 nullnull ,你可以从"multiple nullable variables"创建一个数组:

    fun <T : Any> arrayOfNotNullOrNull(vararg elements: T?): Array<T>? {
        for (element in elements) {
            if (element == null) {
                return null
            }
        }
        return elements as Array<T>
    }
    

    然后,您可以使用 let 将其用于可变数量的值:

    fun example(first: String?, second: String?) {
        arrayOfNotNullOrNull(first, second)?.let {
            // Do something just if both are != null
            // e.g. val (notNullFirst, notNullSecond) = it ...
        }
    }
    

    如果您已经在集合中拥有可以为空的值,则可以创建类似于kotlin.collections.requireNoNullsnoNullsOrNull 扩展函数,但返回 null 而不是抛出异常 .

  • 4

    实际上,你可以简单地做到这一点,你知道吗? ;)

    if (first != null && second != null) {
        // your logic here...
    }
    

    在Kotlin中使用正常的空值检查没有错 .

    对于每个查看代码的人来说,它的可读性更高 .

  • 73

    对于仅检查两个值而不必使用列表的情况:

    fun <T1, T2> ifNotNull(value1: T1?, value2: T2?, bothNotNull: (T1, T2) -> (Unit)) {
        if (value1 != null && value2 != null) {
            bothNotNull(value1, value2)
        }
    }
    

    用法示例:

    var firstString: String?
    var secondString: String?
    ifNotNull(firstString, secondString) { first, second -> Log.d(TAG, "$first, $second") }
    

相关问题