Scala:由于 JVM 的限制,方法不是函数?

问题描述 投票:0回答:1

我发现在 Scala 中经常提到类似的尝试

def f(x: Int): Int = x*x
val g = f // note the missing type

这是不可能的,因为“JVM 如何处理方法的潜在限制”。

   error: missing argument list for method f
   Unapplied methods are only converted to functions when a function type is expected.
   You can make this conversion explicit by writing `f _` or `f(_)` instead of `f`.

还是以下

List[Int](1, 2, 3, 4).map(f)

确实有效。当然,

map
中需要一个函数。但这很令人惊讶,因为我没有看到
g = f
中的歧义。
f
是一个单一参数的方法,
f
不能是简单的调用。

还有 while 方法和函数对象,定义如下

val ff: Int => Int = x => x*x

在 Scala 中不一样,我不知道为什么 Scala 不能只拥有函数对象。

那么导致这些怪癖的 JVM 限制到底是什么?

scala functional-programming jvm
1个回答
0
投票

我发现在 Scala 中经常提到类似的尝试

def f(x: Int): Int = x*x
val g = f

这是不可能的,因为“JVM 如何处理方法的潜在限制”。

嗯,这取决于您到底期望

g
是什么? 如果您希望它只是一个调用
f
的函数,那么做起来非常简单,您只需要多一点语法即可:

// All these three work.
val g = (x: Int) => f(x)
val g = f(_)
val g: Int => Int = f

方法创建函数自动称为“eta扩展”,并且仅在类型已知时由编译器完成,如上面的第三个

val g
示例或在
list.map(f)
情况中.


现在,如果您期望

g
方法
f
的别名,那么这是不可能的。
因为
g
是一个 ,并且在语言中 方法 不是

这可能是由于 JVM 的限制,但最终只是创建者所做的设计选择。


我不知道为什么 Scala 不能只拥有函数对象。

因为,最初,在 Scala 2 中,方法比函数更强大。

例如,函数不能有类型参数、不能接收

implicit
值、不能重载等等

Scala 3 创建了一系列功能来减少这些限制,例如上下文函数 (

A ?=> B
) 和 lambda 类型(
[X] =>> F[X]
)
。但方法仍然有一些独特的东西,比如重载。

此外,由于 JVM 的工作方式,您无论如何都需要方法。因为归根结底,函数只是一个对象/值,附加了

apply
方法

还有性能参数,因为如果我们只有函数,那么就会有很多间接,最终不得不在运行时调用方法


话虽如此,理论上,该语言可以抽象出所有这些内部细节,只具有函数,使函数变得特殊,并且编译器可以将大多数内容内联到类中的方法等等。

但是,不这样做可能有很多原因。我不知道真实的,但我可以想象一些看似合理的:

  • 生成的代码可能会更慢且浪费。
  • 编译器的额外工作。从某种意义上说,它会更慢,也更难维护。
  • 与其他 JVM 语言(如 Java)进行更严格的互操作(在早期 Scala 时代,没有那么多本地库,仅这一点就是一个很大的禁忌)
© www.soinside.com 2019 - 2024. All rights reserved.