внутренний DSL kotlin, использующий инфиксные функции для большей ясности - PullRequest
0 голосов
/ 24 октября 2018
kotlin 1.2.71

У меня есть следующий DSL, который я пишу, и я хочу, чтобы он был как можно ближе к этому образцу:

android {
      compileSdkVersion 26
      buildToolsVersion "28.0.3"
}

Я делаю это, используя инфиксные функции, лямбду и приемники.Внутри моего 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"
    }

1 Ответ

0 голосов
/ 30 октября 2018

Чтобы уточнить: вам не нужно 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"
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...