调用接口中声明的接收函数

Invoke receiver function declared in interface

我正在尝试为个人项目创建一个易于使用的 html 生成器。我想我会使用扩展函数来生成一个 html 以编程方式使用这样的东西:

html {
    head {
        title("Site title")
    }
    body {
        div {
            // stuff in div
        }
    }
}

为此我声明了一个接口:

fun interface TagBlock {
    operator fun Tag.invoke()
}

其中 Tag 将是指定特定标签的 class,例如 htmlbodydiv 等:

class Tag(val name: String)

我现在尝试创建一个接受前面提到的接口和 returns 标签的函数:

fun html(block: TagBlock): Tag {
    val html = Tag("html")
    // invoke `block` with `html`
    return html
}

我对如何调用提供的参数感到困惑 block。以下均无效:

block(html) // Unresolved reference
block.invoke(html) // unresolved reference
html.block() // Unresolved reference: block

我哪里做错了?

您声明的 invoke() 运算符有 2 个接收者:

  • 发送接收者TagBlock
  • 显式接收者Tag

您需要在调用的上下文中提供调度接收器,它才能工作。您可以使用库函数 with():

fun html(block: TagBlock): Tag {
    val html = Tag("html")
    with(block) {
        html.invoke()
    }
    return html
}

不过,这可能是也可能不是您正在寻找的使用体验。

Kotlin 中更惯用的方法是仅将函数类型作为输入:

fun html(block: Tag.() -> Unit): Tag {
    val html = Tag("html")
    html.block()
    return html
}