Kotlin内部DSL,使用infix函数来增加清晰度

时间:2018-10-24 07:37:41

标签: kotlin

kotlin 1.2.71

我正在编写以下DSL,并希望使其尽可能接近此样本:

android {
      compileSdkVersion 26
      buildToolsVersion "28.0.3"
}

我正在使用中缀函数,lambda和接收器来执行此操作。在DSL内,我必须使用it关键字,否则无法使用infix函数。只是想知道是否有办法做到这一点?

另一个问题:在我的infix函数中,是否需要将其用作扩展函数并在其键盘前面加上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"
    }

1 个答案:

答案 0 :(得分:4)

要澄清一下:it不需要infix才能工作。您也可以只写this,例如this compileSdkVersion 26

还请注意,只需具备以下条件即可:

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

然后,用法仅与您显示的=不同:

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

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

关于您提到的另一点,您需要提供扩展功能。您不需要。只需将infix fun Android.buildToolsVersion放在class Android内而不用Android.就可以了,例如:

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

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

fun toConsolePrint() = "compileSDK: $compileSdkVersion build tools: $buildToolsVersion"

这实际上是功能的用途……当然:如果您不喜欢方括号,您仍然可以对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"
}