Kotlin任何与lambdas
虽然提供这个问题的代码是相当微不足道的,但问题集中在类型安全的更一般的方面:
让我们有这样一个lambda函数:
{it: (Any) -> Any -> it(it)}
它需要另一个lambda并将其自身作为参数执行。 所以让我们做一些明显的事情,并将其作为参数调用:
{it: (Any) -> Any -> it(it)}.apply { this.invoke(this) }
但是,这并不如我想的那样工作:在编译时出现以下错误:
类型不匹配:推断的类型是((任何) – >任何) – >任何,但(任何) – >任何预期
好。 所以我们来试试这个:
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) }
区别在哪里?
好的,正如我在评论中所说的那样,在这个问题提出的方式中,有很多不相干的混乱。 我们开始清理一下:
val fn1 = {x1: (Any) -> Any -> x1(x1)}
fn1
的类型是((Any) -> Any) -> Any
。 x1
的类型是(Any) -> Any
。 上面的定义编译。 Kotlin编译器没有任何问题,看到x1
是一个Any
。
虽然尝试调用fn1
本身不起作用。 …和编译器说明了原因: fn1
是一个((Any) -> Any) -> Any
函数,不能用作(Any) -> Any
。 为什么不行? 那么,因为有人可能会援引论点!
为便于讨论,我们创建第二个函数,与第一个函数非常相似:
val fn2 = {x2: (Any) -> Any -> x2("foo")}
它也编译,很好。 现在这个问题归结为:
为什么不工作: fn2(fn1)
但在这一点上应该是显而易见的。 如果这个调用起作用(不管涉及多少apply
或invoke
欺骗),调用x2
(在fn2
内部)的尝试是行不通的,因为x2
是fn1
的别名。 这是一个调用fn1
的参数"foo"
,它期望一个函数。
tl; dr:函数在它们的参数类型中是相反的