Kotlin: функция высшего порядка, принимающая vararg lamba-with-receiveer, где получатель принимает аргументы

Я пытаюсь обернуть иерархию Java-компоновщиков в компоновщик с безопасным типом Kotlin. Иерархия состоит из следующих строителей (и их целей):

  • FigureBuilder (рисунок)
  • LayoutBuilder (Макет)
  • TraceBuilder (Трассировка)

В Java у FigureBuilder есть один метод, который принимает Layout, и другой, который принимает n трасс, используя метод varargs, называемый addTraces():

addTraces(Trace... traces)

Процесс сборки в Java в основном

Figure f = Figure.builder()
   .layout(
       Layout.builder()
           .title("title")
           .build())
   .addTraces(
       ScatterTrace.builder()
           .name("my series")
           .build())
   .build();       

В Kotlin у меня есть код, который создает конструктор фигур и компоновщик, но я застрял на компоновщике трассировки. Мой код до сих пор выглядит так:

 val figure = figure {
            layout {title("Wins vs BA")}

            addTraces(
                ScatterTrace.builder(x, y)
                    .name("Batting avg.").build()
            )
        }


fun figure(c: FigureBuilder.() -> Unit) : Figure {
    val builder = Figure.builder()
    c(builder)
    return builder.build()
}

fun FigureBuilder.layout(c: Layout.LayoutBuilder.() -> Unit) {
    layout(Layout.builder().apply(c).build())
}

// won't compile: ScatterTrace.builder() requires 2 args
fun FigureBuilder.traces(vararg c: ScatterTrace.ScatterBuilder.() -> Unit) {
    c.forEach {
        val builder = ScatterTrace.builder()
        it(builder)
        addTraces(builder.build())
    }
}

Я совсем не уверен, что последняя функция сработает, если я смогу ее скомпилировать, но проблема с немедленной блокировкой заключается в том, что ScatterTrace.builder() принимает два аргумента, и я не могу понять, как передать их в лямбду.

Большое спасибо

2 ответа

Решение

Странно, что в Java можно создавать ScatterTrace.builder без аргументов, но в Kotlin вам нужно два аргумента для его построения. Может быть, будет лучше применять следы один за другим?

fun FigureBuilder.traces(x: Int, y: Int, c: ScatterTrace.ScatterBuilder.() -> Unit) {
    val builder = ScatterTrace.builder(x, y)
    c(builder)
    addTraces(builder.build())
}

val figure = figure {
    layout { title("Wins vs BA") }

    addTraces(
        trace(x, y) { name("Batting avg.") },
        trace(x, y) { name("Batting avg. 2") },
        trace(x, y) { name("Batting avg. 3") }
    )
}
fun FigureBuilder.traces(vararg c: ScatterTrace.ScatterBuilder.() -> Unit) {
    addTraces(
            *c.map {
                val builder = ScatterTrace.builder()
                builder.build()
            }.toTypedArray()
    )
}

должен делать то, что вы ищете с вашим требованием vararg.

Другие вопросы по тегам