【问题标题】:Can I use a name of the lambda as the parameter passed "outside of parentheses"?我可以使用 lambda 的名称作为“括号外”传递的参数吗?
【发布时间】:2017-12-22 00:14:29
【问题描述】:

我可以在括号外写一个 lambda 表达式,但我不能按名称把它放在那里。我尝试了很多方法:

val plus3: (Int,Int,Int)->Int = {a,b,c->a+b+c}
println(apply3(1,2,3){a,b,c->a+b+c})  // OK
println(apply3(1,2,3){plus3}) // Type mismatch. Required: Int, Found: (Int,Int,Int)->Int
println(apply3(1,2,3){(plus3)}) // Type mismatch. Required: Int, Found: (Int,Int,Int)->Int
println(apply3(1,2,3)plus3)   // unresolved reference 
println(apply3(1,2,3){plus3()})   // value captured in a closure
println(apply3(1,2,3){(plus3)()})   // value captured in a closure

把名字放在那里(括号外)的语法是什么?

我不知道为什么,但是在documentation 中没有关于主题的词。它说我们可以把 lambda 放在那里,但没有一个关于表示该 lambda 的变量或常量的词。

【问题讨论】:

  • 那是因为你不能。那是因为没有理由:/
  • @OliverCharlesworth 替换是最基本的逻辑规则。名称理论高于逻辑。如果它被破坏,则应解释该案例并由更具体的规则涵盖。对话“为什么? - 因为!”即使是儿童游戏也不有趣。
  • 答案中已经解释过文档说您需要提供 lambda 表达式,因此没有歧义。我也给了你一个理由——没有令人信服的理由允许这样做。你还需要什么?
  • @OliverCharlesworth 我需要为一个项目选择语言。我认为 Kotlin 是一个伪装者。但正如我所见,Java 或 Groovy 函数式编程更加一致。没有任何客观原因的禁止会导致错误和误解。
  • @Gangnus 如果这是您的担忧,Java 肯定也不例外。例如。 “如果 lambda 表达式出现在程序中的赋值上下文(第 5.2 节)、调用上下文(第 5.3 节)或强制转换上下文(第 5.5 节)之外的某个地方,则这是一个编译时错误。”在docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27plus3 之类的变量在其他上下文中也有效。

标签: intellij-idea lambda functional-programming kotlin


【解决方案1】:

我不知道为什么,但在文档中没有关于主题的文字。

是的,有:

在 Kotlin 中,有一个约定,如果函数的最后一个参数是一个函数,并且你传递一个 lambda 表达式作为相应的参数,你可以在括号外指定它

plus3 是标识符而不是 lambda 表达式,因此您不能在括号外指定它。

plus3的类型是(Int,Int,Int->Int)。与 {a,b,c->a+b+c} 相同。再看看我从 Kotlin 编译器得到的消息。

您的意思是传递{ plus3 } 时的错误消息?根据 Kotlin 规则,{ plus3 } 是一个忽略其参数(如果有)并返回 plus3 的 lambda。所以规则适用,apply3(1,2,3){plus3} 的含义与apply3(1,2,3,{plus3}) 相同。

它将 plus3 视为 Int。

恰恰相反:它希望看到 Int 作为 lambda 的返回值,并看到 plus3(Int,Int,Int) -> Int

所以,这里的问题不在于高深的哲学性质,而似乎是纯粹的句法。

这正是我的观点:该规则是纯粹的语法,它在编译器知道plus3 的类型或值之前应用,因此它不知道也不关心这个值是否恰好是一个 lambda。

规则可以改为说

在 Kotlin 中,有一个约定,如果函数的最后一个参数具有函数类型,则可以在括号外指定它

在这种情况下apply3(1,2,3) plus3 会起作用。但事实并非如此。

【讨论】:

  • 我已经读过了。不要忘记我总是可以使用名称而不是名称所表示的东西。这是名字的感觉。这部分逻辑(名称理论)甚至比布尔逻辑更为基础。 (最后只适用于集合)如果一套规则不符合逻辑,它必须直言不讳地以非常清楚的方式解释这个地方。我没有看到任何关于这个的消息。
  • plus3 不表示表达式,它表示变量。
  • 不,plus3 是一个常数。但即使它是一个变量,它也具有价值并且......我已经解释过了。替换规则应该有效。
  • 1.不,不是,它是一个局部变量(如果它是在方法中定义的)或属性。 2. 是的,它有价值。这个值不是 lambda 表达式,而是这个表达式的值。
  • 您似乎将plus3 视为扩展为 lambda 的宏。它根本不是。就像你有 val plus3 = foo(0) 一样,foo 不会在每次使用 plus3 时被调用。
【解决方案2】:

将 lambda 表达式放在函数调用的括号外与将其放在括号内相同,如下所示:

println(apply3(1, 2, 3, { a, b, c -> a + b + c }))

从这里,我们可以简单地将 lambda 分配给 val(正如您所做的那样),结果是:

val plus3: (Int, Int, Int) -> Int = { a, b, c -> a + b + c }
println(apply3(1, 2, 3, plus3))

【讨论】:

  • 优秀。如果相同,请放在外面。
猜你喜欢
  • 2018-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-12-29
  • 1970-01-01
  • 2016-08-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多