将嵌套闭包调用委托给相应的类

我正在试图在kotlin中实现gradle插件来支持这样的结构

 env { app ("ghc-haskell") { srcLink { "http://downloads.haskell.org/~ghc/8.0.1/ghc-8.0.1-x86_64-unknown-mingw32.tar.xz" } downloadPath { project(':').projectDir.absolutePath + "\\applications\\plugin" } installPath { project(':').projectDir.absolutePath + "\\applications\\plugin" } } } 

但是我有一个像srcLinkdownloadPathinstallPath这样的内部闭包问题。 如何将其调用委托给相应的kotlin类?

我的扩展看起来像这样

 /** * Keeps all environments. */ open class ApplicationEnvironmentContainerExtension { val environs = mutableMapOf<String, ApplicationEnvironmentExtension>() fun app(id: String, closure : ApplicationEnvironmentContainerExtension.() -> String) : ApplicationEnvironmentExtension { val extension = ApplicationEnvironmentExtension() extension.installationId = id environs.put(id, extension) return extension } /** * Sub extension. */ open class ApplicationEnvironmentExtension { var installationId = "" var srcLink = "" var downloadPath = "" var installPath = "" fun srcLink(closure: ApplicationEnvironmentExtension.() -> String) { srcLink = closure() } fun downloadPath(closure: ApplicationEnvironmentExtension.() -> String) { downloadPath = closure() } fun installPath(closure: ApplicationEnvironmentExtension.() -> String) { installPath = closure() } override fun toString(): String { return "ApplicationEnvironmentExtension(" + "installationId='$installationId', " + "srcLink='$srcLink', " + "downloadPath='$downloadPath', " + "installPath='$installPath')" } } } 

当我调用我的print任务来显示环境列表时,它只显示设置的installationId ID – 其他字段是空的

 open class PrintingTask : DefaultTask() { @TaskAction fun print() { val extension = this.project.extensions.getByName("env") as ApplicationEnvironmentContainerExtension extension.environs.forEach { println(it.value) } } } 

如何将closure调用委托给ApplicationEnvironmentExtension

你永远不要在你的app函数中调用closure参数。 我认为app功能的签名是错误的。 应该是这样的:

 fun app(id: String, closure: ApplicationEnvironmentExtension.() -> Unit) 

这使得在闭包中的this参考ApplicationEnvironmentExtension 。 这使得对srcLinkdownloadPathinstallPath的调用命中正确的对象。

然后你通过这样做来调用闭包:

 val extension = ApplicationEnvironmentExtension() extension.closure() 

这将填充ApplicationEnvironmentExtension

我也认为srcLinkdownloadPathinstallPath函数的签名是错误的。 他们应该像这样定义:

  fun srcLink(closure: () -> String) fun downloadPath(closure: () -> String) fun installPath(closure: () -> String) 

你甚至需要这些功能吗? 你不能将scrLinkdownloadPathinstallPath为属性吗? 即

 env { app ("ghc-haskell") { srcLink = "http://downloads.haskell.org/~ghc/8.0.1/ghc-8.0.1-x86_64-unknown-mingw32.tar.xz" downloadPath = project(':').projectDir.absolutePath + "\\applications\\plugin" installPath = project(':').projectDir.absolutePath + "\\applications\\plugin" } } 

我使用该解决方法解决了该问题。

出于一些奇怪的原因,我传入的app方法中的参数closure总是要解决ApplicationEnvironmentContainerExtension尽管设置是作为ApplicationEnvironmentExtension的关闭,甚至调用它。

所以我决定使用蛮力并在ApplicationEnvironmentExtension创建应该在ApplicationEnvironmentExtension中填充的字段,填充它们并在需要的类中手动设置。

 open class ApplicationEnvironmentContainerExtension { val environs = mutableMapOf<String, ApplicationEnvironmentExtension>() var installationId = "" var srcLink = "" var installPath = "" var downloadPath = "" fun app(id: String, closure : ApplicationEnvironmentExtension.() -> Unit) { val extension = ApplicationEnvironmentExtension() extension.installationId = id environs.put(id, extension) extension.process(closure) extension.setEverything(installationId, srcLink, downloadPath, installPath) } } 

至于关闭,我决定像詹姆斯巴塞特建议他们

 env { app ("ghc-haskell") { srcLink = "http://downloads.haskell.org/~ghc/8.0.1/ghc-8.0.1-x86_64-unknown-mingw32.tar.xz" downloadPath = "$path\\applications\\plugin" installPath = "$path\\applications\\plugin" } app ("mongo-db") { srcLink = "https://fastdl.mongodb.org/win32/mongodb-win32-x86_64-2008plus-ssl-3.4.1-signed.msi" downloadPath = "$path\\applications\\plugin" installPath = "$path\\applications\\plugin" } }