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) {}
}

现在,如果我把它和扩展函数一起使用,

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非常适合写你自己的Domain Specific Languages,也叫type-safe builders.正如你提到的,Anko库就是一个使用DSL的例子.在这里,你需要了解的最重要的语言特性是"Function Literals with Receiver",你已经使用了它:Test.() -> Unit

Function Literals with Receiver - Basics

Kotlin支持"带接收者的函数文本"的概念.这允许在函数体without any specific qualifiers中的函数文本的receiver上调用可见方法.这是非常简单的similar to extension functions,在其中还可以访问扩展中的接收方对象的成员.

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 }

正如您所看到的,这样一个带有receiver的函数literal在这里被当作参数block.这block被简单地执行,并且接收器(T的实例)被返回.在实际操作中,如下所示:

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

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

DSL中带接收器的函数文本

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
}

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.

Benefit

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
}

你的例子

我创建了一个简单的例子来说明你想要什么:

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相关问答推荐

Jetpack Compose中的数字 Select 器问题

映射中列表类型的Kotlin可空接收器?

在Kotlin中求n个ClosedRange实例相交的最常用方法是什么?

Kotlin:类型不匹配:推断的类型已运行,但应等待

为什么在jacksonObjectMapper上将DeserializationFeature.FAIL_ON_IGNORED_PROPERTIES设置为false无效?

为什么会出现Kotlin.Unit错误以及如何修复它?

使用 Compose for Desktop Bundle 文件

是什么让 Kotlin 中的 String 类能够使用方括号?

为什么 android studio 不为所有安全参数生成代码?

如何使用 gradle 脚本 Kotlin 构建文件构建可运行的 ShadowJar?

来自类型参数的属性的自定义 getter

Kotlin - 覆盖方法中的 IllegalArgumentException

验证和 DDD - kotlin 数据类

主机名不能为空

Kotlin解构when/if语句

ObjectAnimator.ofFloat 不能直接在kotlin中取Int作为参数

在 Kotlin 函数上使用 Mokito anyObject() 时,指定为非 null 的参数为 null

可以在函数参数中使用解构吗?

Failure delivering result on activity result

在多平台子元素中使用kapt