Какая функция языка kotlin это

Я изучаю kotlin DSL, в частности Teamcity, и вижу шаблон инициализации, который я еще не совсем понимаю.

ссылка на игровую площадку Kotlin

Вот код

package org.arhan.kotlin

fun main() {
    val project = project {
        configuration {
            step {
                name = "step 1"
                command = "hi"
            }
            
            customstep {
                name = "flang"
                anotherCommand = "derp"
                command = "1111"
            }
        }
    }
    println(project.configurations[0].steps[1].command)
}

fun project(block: Project.() -> Unit): Project {
    return Project().apply(block)
}

fun Project.configuration(block: Configuration.() -> Unit): Configuration {
    val configuration = Configuration().apply(block)
    configurations.add(configuration)
    return configuration
}

fun Configuration.step(block: Step.() -> Unit): Step {
    val step = Step().apply(block)
    steps.add(step)
    return step
}

class Project {
    var configurations = mutableListOf<Configuration>()

    fun build(block: Configuration.() -> Unit) = Configuration().apply(block)
}

class Configuration {
    var steps = mutableListOf<Step>()
}
 
open class Step {
     final lateinit var name: String 
     var command: String = ""
}

open class CustomStep(): Step(){
    var anotherCommand: String = ""
    constructor(init: CustomStep.() -> Unit): this(){
        // what does this do?
        init()
    }
}

fun Configuration.customstep(block: CustomStep.() -> Unit): Step {
    // how is this constructor initialized
    val step = CustomStep(block)
    steps.add(step)
    return step
}

В частности, вопрос заключается в том, как инициализируется класс CustomStep. Требуется лямбда с CustomStep в качестве получателя (это правильная терминология?) .

Затем я вызываю init() в конструкторе, который инициализирует только что созданный CustomStep на основе переданного блока.

Я не уверен, как работает эта инициализация. Точнее, какая именно особенность языка Kotlin здесь используется.

И чем это отличается, если вместо этого я написал это следующим образом?

open class CustomStep(): Step(){
    var anotherCommand: String = ""
    // no constructor
}

fun Configuration.customstep(block: CustomStep.() -> Unit): Step {
    // use apply vs. passing in the block
    val step = CustomStep().apply(block)
    steps.add(step)
    return step
}

Спасибо


person ceiling cat    schedule 22.07.2021    source источник
comment
Я считаю, что это реализация типобезопасного компоновщика.   -  person Slaw    schedule 22.07.2021


Ответы (1)


init() относится к параметру init: CustomStep.() -> Unit:

constructor(init: CustomStep.() -> Unit): this(){
//  vvvv    ^^^^
    init()
}

Вы просто вызываете то, что передали, на this. В конце концов, init нужен CustomStep в качестве получателя. Как и в большинстве ситуаций при вызове чего-либо на this, this можно опустить, что и происходит здесь. В случае customStep вы передали block.

val step = CustomStep(block)

block это бит из main:

{
    name = "flang"
    anotherCommand = "derp"
    command = "1111"
}

Ваша альтернатива CustomStep().apply(block) тоже такая же. Вызов вторичного конструктора, который вы объявили, сначала вызовет первичный конструктор без параметров, как вы объявили как : this(), и требуется. Это то же самое, что и CustomStep(). Затем обе версии вызывают block на this.

person Sweeper    schedule 22.07.2021
comment
о верно. this является неявным. Так что это в основном this.init(), где init() просто имеет кучу сеттеров. Аккуратный! - person ceiling cat; 22.07.2021