kotlin - 调用接口(interface)中声明的接收器函数

标签 kotlin extension-methods

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

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

为此我声明了一个接口(interface):

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

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

class Tag(val name: String)

我现在尝试创建一个接受前面提到的接口(interface)并返回标签的函数:

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
  • 显式接收者标签

您需要在调用上下文中提供调度接收器才能使其正常工作。您可以使用库函数 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
}

关于kotlin - 调用接口(interface)中声明的接收器函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67605390/

相关文章:

java - Kotlin索引使用arraylist不会越界

android - 由于接收器类型不匹配,以下候选人均不负责

c# - 枚举的扩展方法,而不是枚举的实例

"members"上的 C# 扩展方法

android - android studio IDE中的Kotlin编译器预发布问题

android - 如何启动所选 fragment 的 Activity ?

gradle - 无法使用kotlin-multipatform项目

c# - 指定为可选 Func<> 的扩展方法

c# - 为什么 LINQ to SQL 不支持查询运算符 'ElementAt'?

c# - 扩展方法和 GetBytes 实现