Kotlin when(Pair <>),还有其他方法吗?

时间:2018-07-12 22:48:31

标签: kotlin

我有一个when构造,想要在两件事上匹配:

when (activeRequest.verb to activeRequest.resourceType) {
    GET to "all" -> allGet()
    PUT to "foo" -> fooPut()
    GET to "foo" -> fooGet()
    POST to "bar" -> barPost()
    GET to "bar" -> barGet()
    COPY to "bar" -> barCopy()
    DELETE to "bar" -> barDelete()
    else -> logMismatch()
}

使用to对构造函数是唯一的方法吗?配对似乎很奇怪(尽管它可以工作)。我很难找到它,因为类似

的代码片段
for ((key, value) in hashMap) {
    println("$key $value)
}

使我感到很高兴,我应该能够在when代码中执行类似的操作,例如

when (activeRequest.verb, activeRequest.resourceType) {
    (GET, "all") -> allGet()
    (PUT, "foo") -> fooPut()
   ...
    else -> logMismatch()
}

这对眼镜有用吗...如果我想做3件怎么办?

4 个答案:

答案 0 :(得分:3)

循环示例中的语法是destructuring declaration,它基本上是一种语法糖,用于在一行中声明对一个对象的多个成员变量的引用。它不会反过来,因为Kotlin没有用于任意元组的机制。

我无法真正提出一种美观的方法来使用两个以上的变量。我想到的选择是使用基本上像这样的元组工作的enum

enum class Response(val verb: String, val type: String) {

    GET_FOO("GET", "foo"),
    ...
    INVALID("?", "?");

    companion object {
        fun from(verb: String, type: String): Response {
            for(response in values()) {
                if(response.verb == verb && response.type == type)
                    return response
            }

            return INVALID
        }
    }
}

when(Response.from(activeRequest.verb, activeRequest.resourceType)) {
    GET_FOO -> getFoo()
    ...
}

或者使用数组。不幸的是,Kotlin数组的相等性不是按内容排列的,因此最终会产生很多样板,并且when语法看起来也非常好。 (我添加了扩展功能使它更好一些,但我仍然不喜欢它):

fun Array<*>.whenCheat(vararg others: Any?): Boolean {
    return this contentEquals others
}

val array = arrayOf("GET", "foo")
when {
   array.whenCheat("GET", "foo") -> getFoo()
   ...
}

我怀疑,通过对功能的响应图可以更好地解决这类问题。希望其他人会提供更聪明的解决方案。

答案 1 :(得分:1)

另一种替代方法是使用data class。例如:

data class Response(val verb: String, val type: String, val other: Int)

// This is an example of what the functions could be... edit as needed
val all = { _: Response -> "all"}
val some = { _: Response -> "some"}
val unknown = { _: Response -> "unknown"}

val handlers = mapOf<Response, (Response) -> String>(
    Response("GET", "all", 200) to all,
    Response("GET", "some", 400) to some
    // and all your other mappings
)

然后,您可以使用该地图,例如:

val myFun = handlers.getOrDefault(myResponse, unknown)

答案 2 :(得分:0)

  

我想做3件物品怎么办?

使用Triple代替Pair

答案 3 :(得分:0)

如果您只是将数据捆绑到一个类中并覆盖其when方法,则可以将equals与任意数量的项一起使用:

class Person(
        var firstName: String = "",
        var lastName: String = "",
        var age: Int = 0,
        var rate: Int = 0) {

    override fun equals(other: Any?): Boolean {
        val otherPerson = other as Person

        return (
                firstName.equals(otherPerson.firstName) &&
                lastName.equals(otherPerson.lastName) &&
                age.equals(otherPerson.age) &&
                rate.equals(otherPerson.rate))
    }

    // just to avoid warning
    override fun hashCode(): Int {
        return super.hashCode()
    }
}

fun main(args: Array < String > ) {
    val p = Person("John", "Doe", 18, 2)
    when (p) {
        Person("Nick", "Doe", 18, 2) -> println("found at 1")
        Person("John", "Doe", 18, 2) -> println("found at 2")
        Person("Maria", "Doe", 18, 2) -> println("found at 3")
        else -> println("not found")
    }
}