How would I write this in idiomatic Kotlin?

2019-08-24 18:48发布

问题:

I have some code:

private fun getTouchX(): Int {
    arguments ?: return centerX()

    return if (arguments.containsKey(KEY_DOWN_X)) {
        arguments.getInt(KEY_DOWN_X)
    } else {
        centerX()
    }
}

private fun centerX() = (views.rootView?.width ?: 0) / 2

and I want to shorten it.

in the function getTouchX, there are two return conditions duplicated. (which is centerX)

I tried to do this:

 private fun getTouchX(): Int {
    if (arguments == null || !arguments.containsKey(KEY_DOWN_X)) {
        return centerX()
    }
    return arguments.getInt(KEY_DOWN_X)
}

However, it looks more like Java than Kotlin.

How could I go about writing this in idiomatic Kotlin?

回答1:

I'm not sure where arguments is coming from, but a cleaner solution would be

private fun getTouchX(): Int =
    if(arguments?.containsKey(KEY_DOWN_X) == true) {
        arguments.getInt(KEY_DOWN_X)
    } else {
        centerX()
    }

The if only calls containsKey if arguments is non-null, otherwise the left side of == resolves to null. null != true, so it will return centerX() from else.

Similarly if arguments is non-null, then the result of containsKey will be used to resolve.

And now that there's only one expression, can use body expression format.



回答2:

I'd probably go with an expression function with a when expression:

private fun getTouchX() = when {
   arguments == null || !arguments.containsKey(KEY_DOWN_X) -> centerX()
   else -> arguments.getInt(KEY_DOWN_X)
}

You could also consider declaring touchX as a private val:

private val touchX: Int
    get() = when {
       arguments == null || !arguments.containsKey(KEY_DOWN_X) -> centerX()
       else -> arguments.getInt(KEY_DOWN_X)
    }


回答3:

Looking at just the plain Kotlin code, my suggestion would be:

    private fun getTouchX() =
        arguments?.let {
            if (!it.containsKey(KEY_DOWN_X))
                return@let null
            it.getInt(KEY_DOWN_X)
        } ?: centerX()

But if arguments is a descendent of an Android BaseBundle, you might further compress this to:

private fun getTouchX() = arguments?.getInt(KEY_DOWN_X, centerX()) ?: centerX()

Note: As the method signature suspiciously looks like reading a property, you might consider turning it into a read-only property.



标签: kotlin