使用中缀功能的kotlin内部DSL增加了更多的清晰度

ant*_*009 6 kotlin

kotlin 1.2.71
Run Code Online (Sandbox Code Playgroud)

我有以下我写的DSL,并希望尽可能接近这个样本:

android {
      compileSdkVersion 26
      buildToolsVersion "28.0.3"
}
Run Code Online (Sandbox Code Playgroud)

我这样做是使用中缀函数和lambda和接收器.在我的DSL里面我必须使用it关键字,否则我无法使用中缀功能.只是想知道,如果有办法做到这一点?

另一个问题:在我的中缀函数中,我是否需要将其用作扩展函数并将其作为Android键盘前缀 infix fun Android.buildToolsVersion(...)

fun main(args: Array<String>) {

    val androidConfig = android {
        it buildToolsVersion  "28.0.3"
        it compileSdkVersion 26
    }

    println(androidConfig.toConsolePrint)
}

private fun android(block: Android.(Android) -> Unit): Android {
    val android = Android()

    android.block(android)

    return android
}

class Android(var compileSdkVersion: Int = 0,
              var buildToolsVersion: String = "") {

    infix fun Android.buildToolsVersion(buildToolsVersion: String) {
        this.buildToolsVersion = buildToolsVersion
    }

    infix fun Android.compileSdkVersion(sdkVersion: Int) {
        compileSdkVersion = sdkVersion
    }
}

private val Android.toConsolePrint: String
    get() {
        return "compileSDK: $compileSdkVersion build tools: $buildToolsVersion"
    }
Run Code Online (Sandbox Code Playgroud)

Rol*_*and 5

为了澄清:你不需要itinfix工作。你也可以直接写this,例如this compileSdkVersion 26.

另请注意,只需具备以下内容即可:

fun android(block: Android.() -> Unit) = Android().apply(block)
class Android(var compileSdkVersion: Int = 0,
              var buildToolsVersion: String = "")
Run Code Online (Sandbox Code Playgroud)

用法与=您显示的内容仅相差 a :

val androidConfig = android {
  buildToolsVersion = "28.0.3"
  compileSdkVersion = 26
}
Run Code Online (Sandbox Code Playgroud)

但好处更大:维护的代码要少得多;-)

关于您提到的另一点,您需要提供扩展功能。你不需要。只需将infix fun Android.buildToolsVersion内部放置在class Android没有 the的情况下Android.就可以了,例如:

class Android(var compileSdkVersion: Int = 0,
              var buildToolsVersion: String = "") {
  infix fun buildToolsVersion(buildToolsVersion: String) {
    this.buildToolsVersion = buildToolsVersion
  }
Run Code Online (Sandbox Code Playgroud)

现在关于consolePrint. 这对我来说看起来也相当复杂。那么下面的内容class Android呢?

fun toConsolePrint() = "compileSDK: $compileSdkVersion build tools: $buildToolsVersion"
Run Code Online (Sandbox Code Playgroud)

这就是函数的实际用途......当然:如果你不喜欢括号,你仍然可以使用你的方法get(),但它听起来像一个函数,它的作用就像一个函数,所以它可能也是一个函数;-)

仅添加差异的完整示例()=

fun main() {
  val androidConfig = android {
    buildToolsVersion = "28.0.3"
    compileSdkVersion = 26
  }
  println(androidConfig.toConsolePrint())
}

fun android(block: Android.() -> Unit) = Android().apply(block)
class Android(var compileSdkVersion: Int = 0,
              var buildToolsVersion: String = "") {
  fun toConsolePrint() = "compileSDK: $compileSdkVersion build tools: $buildToolsVersion"
}
Run Code Online (Sandbox Code Playgroud)