将`Pair`表示的新键值添加到`MutableMap`

时间:2016-09-16 22:04:01

标签: kotlin

我目前这个课程的dsl类似于建筑能力

class GRLMessage {
    var headerMap : MutableMap<String, String> = mutableMapOf()
    lateinit var methodType : GRLMethod
    lateinit var multipartObject : IGRLMultipart

    fun message(closure: GRLMessage.() -> Unit) : GRLMessage {
        closure()
        return this
    }

    fun method(closure: GRLMessage.() -> GRLMethod) : GRLMessage {
        methodType = closure()
        return this
    }

    fun headers(closure: GRLMessage.() -> Unit) : GRLMessage {
        closure()
        return this
    }

    fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
        var pair = closure()
        headerMap.put(pair.first, pair.second)
        return this
    }

    fun multipart(closure: GRLMessage.() -> IGRLMultipart) : GRLMessage {
        multipartObject = closure()
        return this
    }
}

我就像这样测试

class GRLMessageTest {

    data class DummyMultipart(val field: String) : IGRLMultipart {
        override fun getContent() {
            this
        }
    }

    @Test fun grlMessageBuilderTest() {
        val grlMessage = GRLMessage().message {
            method { GRLMethod.POST }
            headers {
                header { Pair("contentType", "object") }
                header { Pair("objectType", "DummyMultipart") }
            }
            multipart { DummyMultipart("dummy") }
        }

        val multipart = DummyMultipart("dummy")
        val headers = mapOf(
                Pair("contentType", "object"),
                Pair("objectType", "DummyMultipart")
        )
        val method = GRLMethod.POST

        assertEquals(multipart, grlMessage.multipartObject)
        assertEquals(method, grlMessage.methodType)
        assertEquals(headers, grlMessage.headerMap)
    }
}

但是尽管提供了

header { Pair("contentType", "object") }

我仍然需要在closure方法中评估header并直接评估put密钥和值到我的MutableMap

fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
    var pair = closure()
    headerMap.put(pair.first, pair.second)
    return this
}

是否有更好的方法将条目添加到Map

3 个答案:

答案 0 :(得分:2)

您的headerMap是否需要变量?如果没有,您可以将其更改为val并使用headerMap += closure()

答案 1 :(得分:1)

添加extension function会使您的流利方法更加流畅:

fun <T: Any> T.fluently(func: ()->Unit): T {
    return this.apply { func() } 
}

这样你的流利功能总是清楚它的回归:

fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
    return fluently { headerMap += closure() }
}

这与以下内容完全相同:

fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
    return this.apply { headerMap += closure() }
}

但扩展功能增加了可读性。

上面我使用@Ruckus给出的答案来解决您向Pair添加headerMap的具体问题。但是,对于DSL的其他用例,您可能还想了解其他选项......

您可以使用letapplywith,这样可以对closure()调用的结果进行任何类型的分解(可能比{{1}更复杂}} 在将来)。所有这些基本相同,减去它们的结果值

Pair

如果您想要处理with(closure()) { headerMap.put(this.first, this.second) } closure().apply { headerMap.put(this.first, this.second) } closure().let { headerMap.put(it.first, it.second) } 允许可以为空的返回的情况,那么使用letapply很不错,在这种情况下,您可能只想在closure()时才采取行动}:

null

关于您的代码的其他说明:

    除非您别无选择,否则
  • 使用closure()?.apply { headerMap.put(this.first, this.second) } closure()?.let { headerMap.put(it.first, it.second) } 代替val
  • var(或类似的lateinit)似乎很危险,无法在不受控制的生命周期中使用,因为错误信息会让人感到困惑,并且会在某个意外时间发生。未来。可能还有其他方法可以通过DSL链接调用来创建更多的多步语法来解决这个问题
  • 您只需在作业的一侧添加类型即可缩短代码,例如:

    Delegates.notNull()

    而不是

    val myMap = mutableMapOf<String, String>()
    

答案 2 :(得分:0)

现在作为解决方案,我为MutableMap

创建了扩展程序
fun MutableMap<String, String>.put(pair : Pair<String, String>) {
    this.put(pair.first, pair.second)
}

这让我这样写了

fun header(closure: GRLMessage.() -> Pair<String, String>) : GRLMessage {
    headerMap.put(closure())
    return this
}