处理这种情况的最佳方式,其中"智能演员是不可能的"

时间:2016-08-31 09:49:14

标签: kotlin

我想知道处理这种情况的最佳方法是什么

class Person(var name:String? = null, var age:Int? = null){
    fun test(){
        if(name != null && age != null)
            doSth(name, age) //smart cast imposible
    }

    fun doSth (someValue:String, someValue2:Int){

    }
}

调用doSth方法并确保名称和年龄为nt null的最简单方法是什么?

我正在寻找一些简单的东西,就像一个变量场景我只想使用let

name?.let{ doSth(it) } 

7 个答案:

答案 0 :(得分:9)

您可以根据需要嵌套let

fun test(){
    name?.let { name ->
        age?.let { age ->
            doSth(name, age) //smart cast imposible    
        }
    }
}

另一种可能更容易理解的方法是使用局部变量:

fun test(){
    val name = name
    val age = age
    if(name != null && age != null){
        doSth(name, age)
    }
}

最后但同样重要的是,请考虑将Person更改为不可变,如下所示:

data class Person(val name:String? = null, val age:Int? = null){
    fun test(){
        if(name != null && age != null){
            doSth(name, age)
        }
    }
    ...
}

答案 1 :(得分:3)

为了使演员成为可能,你必须以某种方式制作价值的本地副本。在Kotlin中,最好明确地完成:

val name = name
val age = age
if(name != null && age != null){
    doSth(name, age)
}

let函数隐藏在抽象层后面,这不是最好的恕我直言。

答案 2 :(得分:2)

有一个很好的小lib允许编写let - 就像有多个变量的代码一样。它是开源的,你可以在GitHub上找到它,它被称为Unwrap

基于自述文件的示例:

unwrap(_a, _b, _c) { a, b, c ->
    println("$a, $b$c") // all variables are not-null
}

所有unwrap(...)方法都标记为inline,因此使用它们不应有任何开销。

顺便说一下,当有一些空变量(nah()方法)时,这个lib也允许处理情况。

答案 3 :(得分:0)

如果你想把它变得有点“极端”,你可以在Pair<String?,Int?>上定义一个为你隐藏逻辑的扩展函数:

fun Pair<String?,Int?>.test(block: (String, Int) -> Unit) {
    if(first != null && second != null) {
         block(first, second)
    }
}

然后,调用它会更简洁

(name to age).test { n, a ->
   println("name: $n age: $a")
}

然而,它并没有真正帮助你(因为你可以将它定义为Person类本身内部的一个函数),除非你在整个项目中经常需要这种功能。就像我说的那样,这似乎有些过分。

修改 你可以通过完全通用来实现它(有点)更有用:

fun <T,R> Pair<T?,R?>.ifBothNotNull(block: (T, R) -> Unit) {
    if(first != null && second != null){
         block(first, second)
    }
}

答案 4 :(得分:0)

除了miensol&#39; answer之外,还有多种方法可以将属性值复制到函数变量中以启用智能强制转换。 e.g:

  1. 中介功能:

    class Person(var name: String? = null, var age: Int? = null) {
        fun test() = test(name, age)
        private fun test(name: String?, age: Int?) {
            if (name != null && age != null)
                doSth(name, age) //smart cast possible
        }
    
        fun doSth(someValue: String, someValue2: Int) {
    
        }
    }
    
  2. 匿名函数:

    class Person(var name: String? = null, var age: Int? = null) {
        fun test() = (fun(name: String?, age: Int?) {
            if (name != null && age != null)
                doSth(name, age) //smart cast possible
        })(name, age)
    
        fun doSth(someValue: String, someValue2: Int) {
    
        }
    }
    
  3. 默认参数:

    class Person(var name: String? = null, var age: Int? = null) {
        fun test(name: String? = this.name, age: Int? = this.age) {
            if (name != null && age != null)
                doSth(name, age) //smart cast possible
        }
    
        fun doSth(someValue: String, someValue2: Int) {
    
        }
    }
    

答案 5 :(得分:0)

可以定义一个内联方法,允许你采用N个参数,以避免嵌套let s(我的答案基于this)。

inline 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 test() {
    safeLet(name, age, {name, age -> 
        doSth(name, age) //smart cast
    });
}

答案 6 :(得分:0)

我在向textview分配文本时遇到了同样的问题描述。 我所做的只是在我的textview名称后加上双重感叹号。 例如:

var name:TextView?=null
name = findViewById(R.id.id_name)
name!!.text = "Your text"