简体   繁体   English

Kotlin Any with lambdas

[英]Kotlin Any with lambdas

While the code provided with the question is rather trivial, the question focusses on the more general aspect of type safety: 虽然问题提供的代码相当琐碎,但问题集中在类型安全性的更一般方面:

Let's have a lambda function like this: 让我们有一个像这样的lambda函数:

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

It takes another lambda and executes it with itself as a parameter. 它需要另一个lambda并将其本身作为参数执行。 So let's do the obvious and call it with itself as parameter: 因此,让我们做一个显而易见的事情,并以其自身作为参数进行调用:

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

But that does not work as well, as I thought: I get the following error at compile time: 但这并不像我想的那样有效:编译时出现以下错误:

Type mismatch: inferred type is ((Any) -> Any) -> Any but (Any) -> Any was expected 类型不匹配:推断的类型为((Any)-> Any)->除(Any)-> Any以外

Ok. 好。 So let's try this one: 因此,让我们尝试一下:

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

The actual value of this property doesn't matter, I am not interested in the result, just in the compiler behaviour. 该属性的实际值无关紧要,我对结果不感兴趣,仅对编译器行为感兴趣。 So here is another property: 所以这是另一个属性:

 val kappa: (Any) -> Any = lambda

Ok, now this actually compiles. 好的,现在可以编译了。 But isn't that the same thing as before? 但这与以前不一样吗? I am passing a (Any) -> Any function to a property (in the other case it is an argument), that expects a (Any) -> Any function. 我正在将(Any) -> Any函数传递给属性(在其他情况下,它是一个参数),期望使用(Any) -> Any函数。 Logic tells me: Yes, (Any) -> Any is of type Any , because everything is. 逻辑告诉我:是的, (Any) -> Any属于Any类型,因为一切都是如此。 But why doesn't that work with the lambda invocation? 但是,为什么lambda调用不起作用? In fact, I can explicitly cast my lambda to a (Any) -> Any function, which will result in an unchecked cast, but it will compile and execution results in a StackOverflowError as expected. 实际上,我可以将lambda显式转换为(Any) -> Any函数,这将导致未经检查的转换,但是它将按预期进行编译和执行,从而导致StackOverflowError。

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

Where is the difference? 区别在哪里?

Ok, there is, as I said in comments, just a whole lot of irrelevant confusion in the way this question is posed. 好的,正如我在评论中说的那样,在提出这个问题的方式上只存在很多无关紧要的混乱。 Let's start by cleaning some of it up: 让我们从清理其中的一些开始:

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

The type of fn1 is ((Any) -> Any) -> Any . fn1的类型是((Any) -> Any) -> Any The type of x1 is (Any) -> Any . x1的类型是(Any) -> Any The definition above compiles. 上面的定义已编译。 The Kotlin compiler has no trouble seeing that x1 is an Any . Kotlin编译器毫不费力地看到x1Any

The attempt to invoke fn1 on itself, though, doesn't work. 但是,尝试自行调用fn1无效。 ... and the compiler says exactly why: fn1 is a function that is an ((Any) -> Any) -> Any and cannot be used as an (Any) -> Any . ...并且编译器确切说明了原因: fn1是一个函数,该函数是((Any) -> Any) -> Any ,不能用作(Any) -> Any Why doesn't that work? 为什么不起作用? Well, because the somebody might invoke the argument! 好吧,因为有人可能会调用该参数!

So that it is easier to discuss, let's create a second function, very similar to the first: 为了便于讨论,我们创建第二个函数,与第一个函数非常相似:

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

It also compiles, just fine. 它也可以编译,就可以了。 And now this whole question question boils down to: 现在整个问题的问题归结为:

Why doesn't this work: fn2(fn1) 为什么这样做不起作用: fn2(fn1)

But it should be obvious, at this point. 但在这一点上应该很明显。 If that call worked (no matter how much apply or invoke trickery is involved) the attempt to invoke x2 (inside fn2 ) can't work, because x2 is an alias for fn1 . 如果该调用有效(无论涉及多少applyinvoke欺骗),则尝试调用x2 (在fn2内部)都将失败,因为x2fn1的别名。 It is a call to fn1 with the argument "foo" , where it expects a function. 这是对fn1的调用,其参数为"foo" ,它需要一个函数。

tl;dr: Functions are contravariant in their argument types tl; dr:函数的参数类型相反

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM