Kotlin任何有lambdas的人

时间:2017-09-11 18:17:33

标签: lambda kotlin

虽然提供问题的代码相当简单,但问题集中在类型安全的更一般方面:

让我们有一个像这样的lambda函数:

{it: (Any) -> Any -> it(it)}

它需要另一个lambda并将其自身作为参数执行。所以,让我们做一些显而易见的事情并将其作为参数调用:

{it: (Any) -> Any -> it(it)}.apply { this.invoke(this) }

但是这并不像我想的那样好:我在编译时遇到以下错误:

类型不匹配:推断类型为((Any) - > Any) - >除了(任何)之外的任何 - >任何预期的

确定。所以,让我们试试这个:

val lambda: (Any) -> Any = { Unit }

这个属性的实际值并不重要,我对结果不感兴趣,只是在编译器行为中。所以这是另一个属性:

 val kappa: (Any) -> Any = lambda

好的,现在这实际上是编译的。但是和以前一样吗?我将(Any) -> Any函数传递给属性(在另一种情况下,它是一个参数),它需要一个(Any) -> Any函数。逻辑告诉我:是的,(Any) -> Any的类型为Any,因为一切都是。但为什么不能使用lambda调用呢?实际上,我可以显式地将我的lambda转换为(Any) -> Any函数,这将导致未经检查的强制转换,但它将按预期编译并执行StackOverflowError。

{it: (Any) -> Any -> it(it)}.apply { this.invoke(this as (Any) -> Any) }

区别在哪里?

1 个答案:

答案 0 :(得分:0)

好吧,就像我在评论中所说的那样,这个问题提出的方式存在很多无关紧要的混淆。让我们从清理其中一些开始:

val fn1 = {x1: (Any) -> Any -> x1(x1)}

fn1的类型为((Any) -> Any) -> Anyx1的类型为(Any) -> Any。上面的定义编译。 Kotlin编译器可以毫不费力地看到x1Any

但是,尝试调用fn1本身并不起作用。 ...并且编译器确切地说明了原因:fn1是一个((Any) -> Any) -> Any的函数,不能用作(Any) -> Any。为什么不起作用?好吧,因为有人可能会调用这个论点!

为了更容易讨论,让我们创建第二个函数,与第一个函数非常相似:

val fn2 = {x2: (Any) -> Any -> x2("foo")}

它也编译,就好了。现在整个问题归结为:

为什么这不起作用:fn2(fn1)

但在这一点上应该是显而易见的。如果该调用有效(无论涉及多少applyinvoke欺骗),调用x2(在fn2内)的尝试都无效,因为{{1 }}是x2的别名。它是fn1调用fn1参数,它需要一个函数。

tl; dr:函数在其参数类型中是逆变的