我想知道处理这种情况的最佳方法是什么
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) }
答案 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:
中介功能:
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) {
}
}
匿名函数:
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) {
}
}
默认参数:
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"