首页 > 解决方案 > Kotlin:采用 vararg lamba-with-receiver 的高阶函数,其中接收者接受参数

问题描述

我正在尝试将 Java 构建器的层次结构包装在 Kotlin 类型安全构建器中。层次结构由以下构建器(及其目标)组成:

在 Java 中,FigureBuilder 有一个采用 Layout 的方法,另一个采用名为 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() 需要两个参数,我不知道如何将它们传递给 lambda。

非常感谢

标签: kotlinlambdabuilderkotlin-dsl

解决方案


奇怪的是,在 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") }
    )
}

推荐阅读