如何创建 Kotlin DSL - DSL 语法 Kotlin [英] How to create Kotlin DSL - DSL syntax Kotlin

查看:40
本文介绍了如何创建 Kotlin DSL - DSL 语法 Kotlin的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

anko 一样,您可以编写如下回调函数:

As with anko you can write callback functions like this:

alert {
    title = ""
    message = ""
    yesButton {
       toast("Yes") 
    }
    noButton { 
       toast("No")
    }
}

如何创建这样的嵌套函数?我尝试像下面那样创建它,但似乎不起作用.

How can I create a nested functions like that? I tried creating it like below but doesn't seem to be working.

class Test {
    fun f1(function: () -> Unit) {}
    fun f2(function: () -> Unit) {}
}

现在,如果我将其与扩展功能一起使用,

Now, if I use this with extension function,

fun Context.temp(function: Test.() -> Unit) {
    function.onSuccess() // doesn't work
}

从活动中调用:

temp {
    onSuccess {
        toast("Hello")
    }
}

不起作用.我在这里仍然缺乏一些基本概念.有人可以在这里指导吗?

Doesn't work. I am still lacking some basic concepts here. Can anyone guide here?

推荐答案

Kotlin DSLs

Kotlin 非常适合编写您自己的领域特定语言,也称为 类型安全构建器.正如您提到的,Anko 库是一个使用 DSL 的示例.您需要在这里了解的最重要的语言特性称为 "Function Literals使用 Receiver",您已经使用了它:Test.() ->单位

Kotlin DSLs

Kotlin is great for writing your own Domain Specific Languages, also called type-safe builders. As you mentioned, the Anko library is an example making use of DSLs. The most important language feature you need to understand here is called "Function Literals with Receiver", which you made use of already: Test.() -> Unit

Kotlin 支持带有接收器的函数字面量"的概念.这使得在其主体中没有任何特定限定符的情况下,可以在函数文字的接收者上调用可见方法.这非常类似于扩展函数,在扩展函数中也可以访问扩展内部的接收者对象的成员.

Kotlin supports the concept of "function literals with receivers". This enables calling visible methods on the receiver of the function literal in its body without any specific qualifiers. This is very similar to extension functions, in which it’s also possible to access members of the receiver object inside the extension.

一个简单的例子,也是 Kotlin 标准库中最酷的函数之一,是apply:

A simple example, also one of the coolest functions in the Kotlin standard library, isapply:

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

正如你所看到的,这样一个带有接收器的函数文字在这里被当作参数block.这个 block 被简单地执行并返回接收者(它是 T 的一个实例).实际操作如下:

As you can see, such a function literal with receiver is taken as an argument block here. This block is simply executed and the receiver (which is an instance of T) is returned. In action this looks as follows:

val text: String = StringBuilder("Hello ").apply {
            append("Kotliner")
            append("! ")
            append("How are you doing?")
        }.toString()

A StringBuilder 用作接收器,并在其上调用 apply.block{}(lambda 表达式)中作为参数传递,不需要使用额外的限定符,只需调用 append,一个可见的多次使用 StringBuilder 的方法.

A StringBuilder is used as the receiver and apply is invoked on it. The block, passed as an argument in {}(lambda expression), does not need to use additional qualifiers and simply calls append, a visible method of StringBuilder multiple times.

如果你看一下这个来自文档的例子,你会看到这个:

If you look at this example, taken from the documentation, you see this in action:

class HTML {
    fun body() { ... }
}

fun html(init: HTML.() -> Unit): HTML {
    val html = HTML()  // create the receiver object
    html.init()        // pass the receiver object to the lambda
    return html
}


html {       // lambda with receiver begins here
    body()   // calling a method on the receiver object
}

html() 函数需要这样一个函数文字,接收者以 HTML 作为接收者.在函数体中,您可以看到它是如何使用的:创建了一个 HTML 实例,并在其上调用了 init.

The html() function expects such a function literal with receiver with HTML as the receiver. In the function body you can see how it is used: an instance of HTML is created and the init is called on it.

这种高阶函数的调用者需要一个带有接收器的函数文字(如html()),你可以使用任何可见的HTML 没有附加限定符的函数和属性(例如 this),正如您在调用中看到的:

The caller of such an higher-order function expecting a function literal with receiver (like html()) you can use any visible HTML function and property without additional qualifiers (like this e.g.), as you can see in the call:

html {       // lambda with receiver begins here
    body()   // calling a method on the receiver object
}

你的例子

我创建了一个您想要的简单示例:

Your Example

I created a simple example of what you wanted to have:

class Context {
    fun onSuccess(function: OnSuccessAction.() -> Unit) {
        OnSuccessAction().function();
    }

    class OnSuccessAction {
        fun toast(s: String) {
            println("I'm successful <3: $s")
        }
    }
}

fun temp(function: Context.() -> Unit) {
    Context().function()
}

fun main(args: Array<String>) {
    temp {
        onSuccess {
            toast("Hello")
        }
    }
}

这篇关于如何创建 Kotlin DSL - DSL 语法 Kotlin的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆