简体   繁体   中英

How to use kotlin's default parameter only if the input is not null?

Example:

data class Something(val mendatory: String = "default value")

val userInput: String? by SomeTypeOfInputFieldThatReturnsNullable

//val something = Something(userInput)    //not valid because userInput is String?

val something = if (userInput == null) 
                    Something() 
                else 
                    Something(userInput)

Is there some less verbose way to tell kotlin to only pass parameter if it's not null?

Depends on what you mean by less verbose.

One way is using the null-safe-operator ( ?. ) and something like let :

val something = userInput?.let(::Something) 
                         ?: Something()

I leave it up to you whether this is really less verbose.

Another variant is to basically just pass the null -value up to the data class . Either by providing appropriate constructors or by having appropriate factory functions in place. The following is just one of many variants (now using Companion and invoke ):

data class Something(val mandatory: String) {
  companion object {
    operator fun invoke(s : String? = null) = Something( s ?: "default value")
  }
}

Calling it then looks like:

val something = Something(userInput) // if userInput is String? the companion function is called... if it's String, the constructor is used

// or also using invoke:
val something = Something() // now with s = null, leading to "default value"

I can think of a few approaches, but all of them involve repetition somewhere…

If this was the only place you needed the default value, you could move it out of the class:

data class Something(val mandatory: String)

val something = Something(userInput ?: "default value")

Or you could allow the constructor to take a null — but then you'd need to separate the nullable constructor param from the non-null property:

data class Something(mandatoryParam: String?) {
    val mandatory = mandatoryParam ?: "default value"
}

val something = Something(userInput)

Or there are the options Roland outlined in his answer: use let to avoid some of the repetition when deciding which constructor to call; or using a pseudo-constructor on the companion object.

So, no single obvious answer. (I think I'd probably prefer one of the two approaches I've illustrated, depending whether the default value relates in any way to this particular user input, or whether it must necessarily apply however the object gets constructed.)

There are many solutions that the other have explained... The best one is:

val something = userInput?.let(::Something) ?: Something()

But there is another way too, if you change 'val' to 'var':

data class Something(var mendatory: String = "default value")

val userInput: String? by SomeTypeOfInputFieldThatReturnsNullable

val something = Something().apply { userInput?.let { mendatory = userInput } }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM