I wonder what is the best way to handle such scenario
class Person(var name:String? = null, var age:Int? = null){
fun test(){
if(name != null &am
For the cast to be possible you have to make a local copy of the value somehow. In Kotlin this is best done explicitly:
val name = name
val age = age
if(name != null && age != null){
doSth(name, age)
}
The let
function hides this behind an abstraction layer, which is not the best IMHO.
There's a nice, little lib that allows for writing let
-like code with multiple variables. It's open-source and you can find it on GitHub, it's called Unwrap
Example based on readme:
unwrap(_a, _b, _c) { a, b, c ->
println("$a, $b$c") // all variables are not-null
}
All unwrap(...)
methods are marked inline
so there should be no overhead with using them.
By the way, this lib also allows to handle situation when there are some null variables (the nah()
method).
In addition to miensol's answer there are various ways to copy property values into function variables to enable smart cast. e.g.:
Intermediary function:
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) {
}
}
Anonymous function:
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) {
}
}
Default arguments:
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) {
}
}
I was having the problem while assigning text to textview with same problem description. All I did was putting double exclamation mark after the name of my textview. For example:
var name:TextView?=null
name = findViewById(R.id.id_name)
name!!.text = "Your text"
It is possible to define an inline method that allows you to take N parameters in order to avoid nesting let
s (I'm basing my answer on 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
}
Then
fun test() {
safeLet(name, age, {name, age ->
doSth(name, age) //smart cast
});
}
You can nest let
as much as you like so:
fun test(){
name?.let { name ->
age?.let { age ->
doSth(name, age) //smart cast imposible
}
}
}
Another approach, that might be easier to follow, is to use local variables:
fun test(){
val name = name
val age = age
if(name != null && age != null){
doSth(name, age)
}
}
Last but not least, consider changing Person
to be immutable like so:
data class Person(val name:String? = null, val age:Int? = null){
fun test(){
if(name != null && age != null){
doSth(name, age)
}
}
...
}