package yamin

typealias Foo = () -> Unit

fun main() {
    bar {
        baz()
    }
}

fun bar(foo: Foo) {
    foo()
}

context(Foo)
fun baz() {
    //
}

我试图对函数的上下文使用lambda类型,这在这一点上似乎没有问题,但当我试图在该上下文中调用该函数时,或者至少在我认为是该上下文的上下文中,我失败了,而Kotlin的编译器向我显示了baz()的错误:

No required context receiver found: Cxt { context((yamin.Foo /* = () -> kotlin.Unit */)) public fun baz(): kotlin.Unit defined in yamin in file Main.kt[SimpleFunctionDescriptorImpl@7b5e305f] }

也许我误解了Kotlin的上下文接收器,或者我期待的东西不是为它设计的.我只想创建一个只能在特定上下文中调用的函数,在本例中只能在特定的lambda中调用.

推荐答案

就像现在这样,你的baz可以这样称呼:

val someFoo: Foo = {}
with(someFoo) {
    baz()
}

通过使用with,我将() -> Unit的一个实例带入上下文,因此someFoo成为一个上下文接收器,我可以用它来调用baz.在baz中,我可以通过使用this@Foo访问这个someFoo.这就是上下文接收器应该如何工作的.

如果希望baz只能在bar的lambda中调用,则bar的lambda需要使用Receiver参数提供上下文接收器,类似于with的lambda被声明为T.() -> R的方式.

object Foo

fun main() {
    bar {
        baz()
    }
}

fun bar(foo: Foo.() -> Unit) {
    Foo.foo()
}

context(Foo)
fun baz() {
    // ...
}

我把这里的实际背景改成了object,因为据我所知,bar的lambda没有什么特别之处.当然,如果您愿意,可以通过将Foo更改为包含数据的类来使其向baz提供额外信息.

请注意,这不会阻止某人执行以下操作:

with(Foo) {
    baz()
}

如果不在bar之外再添加一层,就很难防止这种情况发生,比如:

// note that bar is no longer a global function
import bar.Foo.Companion.bar

class Foo private constructor() {
    companion object {
        fun bar(foo: Foo.() -> Unit) {
            Foo().foo()
        }
    }
}

context(Foo)
fun baz() {
    // ...
}

您也可以做一些简单的事情来防止它从包之外发生:

sealed interface FooInterface

private object Foo: FooInterface

fun bar(foo: FooInterface.() -> Unit) {
    Foo.foo()
}

context(FooInterface)
fun baz() {
    // ...
}

Kotlin相关问答推荐

Kotlin -从列表中获取特定过滤器的唯一列表值

在调用父构造函数之前重写类属性

当我通过媒体通知更改音乐时不要更新我的 UI

扩展属性委托给实例属性

高效匹配两个 Flux

我什么时候可以在 LazyList 或 Column 的范围内使用 Composable?

为空数组添加值

多次运行espresso测试

在 kotlin 中模拟伴随对象函数

Dagger 2 ContributesAndroidInjector 为模块提供活动

listOf() 返回 MutableList

将 Completable 转换为 Single 的规范方法?

Kotlin-Java 互操作不能与可变参数一起使用

在 Kotlin 中实现 (/inherit/~extend) 注解

Mockito 的 argThat 在 Kotlin 中返回 null

如何将命令行参数传递给Gradle Kotlin DSL

如何在使用Koin DI的活动之间共享同一个ViewModel实例?

android Room 将 Null 作为非 Null 类型返回

如何在 Kotlin 中定义新的运算符?

任务':app:kaptDebugKotlin'的Kotlin执行失败