[英]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编译器毫不费力地看到
x1
是Any
。
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
. 如果该调用有效(无论涉及多少
apply
或invoke
欺骗),则尝试调用x2
(在fn2
内部)都将失败,因为x2
是fn1
的别名。 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.