Kotlin的crossinline关键字

我已经读过这个问题,但我有一个关于crossinline关键字更基本的问题。 我不确定它解决了什么问题,以及如何解决这个问题。

从Kotlin Docs ,

请注意,某些内联函数可能会将传递给它们的lambda作为参数,而不是直接从函数体中调用,而是从另一个执行上下文(如本地对象或嵌套函数)中调用。 在这种情况下 ,lambda中也不允许非本地控制流量。 为了表明 ,lambda参数需要用十字线修饰符标记:

[强调添加]

这个说法对我来说是模棱两可的。 首先,我实际上难以想象“这种情况”是什么意思。 我对这个问题有一个大致的概念,但不能拿出一个好的例子。

其次,“表示”这个短语可以用多种方式来阅读。 指出什么? 那个特定的情况是不允许的? 这允许的吗? 给定函数定义中的非本地控制流是否允许?

简而言之,我很难搞清楚使用这个关键字的上下文是什么,使用它的客户端是什么,以及应用这个关键字的预期结果是什么。

首先,我实际上难以想象“这种情况”是什么意思。 我对这个问题有一个大致的概念,但不能拿出一个好的例子。

这是一个例子:

 interface SomeInterface { fun someFunction(): Unit } inline fun someInterfaceBy(f: () -> Unit): SomeInterface { return object : SomeInterface { override fun someFunction() = f() // ^^^ // Error: Can't inline 'f' here: it may contain non-local returns. // Add 'crossinline' modifier to parameter declaration 'f'. } } 

在这里,传递给someInterfaceBy { ... }的函数被内联在实现SomeInterface的匿名类中。 编译someInterfaceBy的每个调用站点会产生一个具有不同的someFunction()实现的新类。

要查看可能出现的问题,请考虑调用someInterfaceBy { ... }

 fun foo() { val i = someInterfaceBy { return } // do something with `i` } 

在内联lambda中, return是非本地的 ,实际上是指foo返回 。 但是因为lambda没有被调用并泄漏到对象i ,所以foo返回可能是绝对没有意义的:如果在foo已经返回或甚至在不同的线程中调用了i.someFunction() (因此lambda)

一般来说, “这种情况”是指inline函数,它们不是在它们自己的实体中调用它们的函数参数(有效地,即考虑其他内联函数),而是在它们声明的其他函数内部,如非内联lambdas和匿名对象。


其次,“表示”这个短语可以用多种方式来阅读。 指出什么? 那个特定的情况是不允许的? 这是允许的吗? 给定函数定义中的非本地控制流是否允许?

这正是我如何在Kotlin语言设计中解决上述问题的方法:无论何时inline函数试图将其函数参数内联到不能就地调用但稍后存储和调用的地方inline函数的参数应该被标记为crossinline ,表明在这里传递的lambda中不允许非本地控制流。