将一个“Pair”代表的新键值添加到“MutableMap”中

我目前有这个类与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") } 

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

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

有没有更好的方式添加到Map条目?

你的headerMap需要是var吗? 如果没有,你可以把它改成一个val,并使用headerMap += closure()

添加一个扩展函数使得流利的方法更加流畅:

 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给出的答案来解决你添加一个PairheaderMap具体问题。 但是,您还有其他选项可能需要了解其他DSL使用情况。

你可以使用letapply或者其中的任何一种类型来分解closure()调用的结果(或许比将来更复杂一些)。 所有这些基本上是相同的, 减去它们的结果值

 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 (或类似的Delegates.notNull() )在不能保证完成的不受控制的生命周期中使用似乎是危险的,因为错误信息会在未来某个意想不到的时间发生混淆。 还有其他的方法可以解决这个问题,DSL链接调用创建更多的多步语法
  • 您可以通过在作业的一边只有类型缩短代码,例如:

     val myMap = mutableMapOf<String, String>() 

    代替

     var myMap : MutableMap<String, String> = mutableMapOf() 

那么现在作为解决方案,我为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 }