How to declare a variable with two types in Kotlin

2019-07-17 20:27发布

问题:

I'm gonna write a method like:

object UIBehavior {
   fun dialog(context: Context, title: Int | String, message: Int | String){
     val dialogObj = AlertDialog.Builder(context)
     dialogObj.setTitle(title)
     dialogObj.setMessage(message)
   }
}

The methods dialogObj.setTitle and dialogObj.setMessage allow two types of parameters, and how can I delare the parameter that can let the method dialog allow only two types Int and String?

回答1:

You can't do that in Kotlin.

But you can have multiple versions of a function, e.g.

object UIBehavior {
    fun dialog(context: Context, titleId: Int, messageId: Int){
        val titleString = context.getString(titleId)
        val messageString = context.getString(messageId)
        dialog(context, titleString, messageString)
    }

    fun dialog(context: Context, title: String, message: String) {
        val dialogObj = AlertDialog.Builder(context)
        dialogObj.setTitle(title)
        dialogObj.setMessage(message)
    }
}

That way you can simply call the function with either ids or strings and it looks like you are using the same function

UIBehavior.dialog(this, R.string.title, R.string.message)
UIBehavior.dialog(this, "title", "message")

You could also use a common supertype of Int and String but that would allow a lot more and I wouldn't recommend that.

fun dialog(context: Context, title: Any, messageId: Any){
    val titleString = when (title) {
        is String -> title
        is Int -> context.getString(title)
        else -> throw IllegalArgumentException("Unsupported type")
    }
    val messageString = when ...
       ...
    dialog(context, titleString, messageString)
}

Generics don't work here either because you can't call dialogObj.setTitle(title) dynamically. It must be known at compile time whether you want to call the Int or the String overload of that function. It's also not really different from using Any.



回答2:

You could use Generics to have the same method, and check the type in the method body.

Or have two different methods.



回答3:

You could use Any, but I don't think it is a very nice solution at all.

It would be much better to make both the title and message a String or CharSequence in line with the types setTitle and setMessage take as parameters.



回答4:

Thank you guys, I was writing codes

interface DialogOption {
    val title: Any
    val message: Any
    val positiveBtnTxt: Any
    val negativeBtnTxt: Any
    fun confirm(d: DialogInterface, n: Int) {
        d.dismiss()
    }
    fun cancel(d: DialogInterface, n: Int) {
        d.dismiss()
    }

}

object UIBehavior {
    fun dialog(context: Context, opt: DialogOption) {
        val dialogObj = AlertDialog.Builder(context)
        val title = opt.title
        val message = opt.message
        val poTxt = opt.positiveBtnTxt
        val negTxt = opt.negativeBtnTxt
        fun positiveCallback(d: DialogInterface, n: Int) {
            opt.confirm(d, n)
        }

        fun negativeCallback(d: DialogInterface, n: Int) {
            opt.cancel(d, n)
        }

        if (title is String) {
            dialogObj.setTitle(title)
        } else if (title is Int) {
            dialogObj.setTitle(title)
        }
        if (message is String) {
            dialogObj.setMessage(message)
        } else if (message is Int) {
            dialogObj.setMessage(message)
        }
        if (poTxt is String) {
            dialogObj.setPositiveButton(poTxt, ::positiveCallback)
        } else if (poTxt is Int) {
            dialogObj.setPositiveButton(poTxt, ::positiveCallback)
        }
        if ( negTxt is String) {
            dialogObj.setNegativeButton(negTxt, ::negativeCallback)
        } else if (negTxt is Int) {
            dialogObj.setNegativeButton(negTxt, ::negativeCallback)
        }

        dialogObj.show()
    }
}

It works but not sure if it's reasonable



标签: types kotlin