将一个“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给出的答案来解决你添加一个Pair
到headerMap
具体问题。 但是,您还有其他选项可能需要了解其他DSL使用情况。
你可以使用let
, apply
或者其中的任何一种类型来分解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) }
使用let
或apply
是很好的,如果你想处理一个情况,其中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 }