在Scala中使用def或var声明一个函数

Chu*_*ieh 2 scala

我试图找出在Scala中声明函数时def和之间的区别var/val.

假设我们有一个功能:

scala> def f(x: Int) = { x * 2 }
f: (x: Int)Int
Run Code Online (Sandbox Code Playgroud)

另一个功能g:

scala> var g = (x:Int) => x*2
g: Int => Int = <function1>
Run Code Online (Sandbox Code Playgroud)

显然它们在以下方面是相同的:

scala> f(2)
res0: Int = 4

scala> g(2)
res1: Int = 4
Run Code Online (Sandbox Code Playgroud)

但是,我能做到

g = f
g: Int => Int = <function1>
Run Code Online (Sandbox Code Playgroud)

但不是

scala> f = g
<console>:13: error: missing arguments for method f;
follow this method with `_' if you want to treat it as a partially applied function
val $ires6 = f
             ^
<console>:10: error: reassignment to val
       f = g
         ^
Run Code Online (Sandbox Code Playgroud)

问题1:为什么会发生这种情况?我猜那张def地图val.

问题2:如果我在声明g中使用val而不是var,它们是否相同?如果没有,那么有什么区别呢?

然后我尝试:

scala> def three( timetwo:(Int) => Int ) = { timetwo(3) } 
three: (timetwo: Int => Int)Int

scala> three(g)
res47: Int = 6

scala> three(f)
res48: Int = 6
Run Code Online (Sandbox Code Playgroud)

问题3:这是否意味着(x: Int)Int相同Int => Int = <function1>?如果是这样,是否有一些情况我们应该优先于另一方?

事情与_(下划线)有关,

scala> three(f _)
res49: Int = 6

scala> three(g _)
<console>:11: error: type mismatch;
found   : () => Int => Int
required: Int => Int
          three(g _)
                ^
Run Code Online (Sandbox Code Playgroud)

问题4:为什么会发生这种情况?_Scala 中(下划线)的用法是什么?

Gab*_*lla 6

为什么会这样?我猜测def映射到val.

def 是一种方法(以JVM术语),因此分配它是没有意义的.

解析器是那么迷茫,它最终试图通过解释分配保存一天f = g为

val $ires6 = f
f = g
Run Code Online (Sandbox Code Playgroud)

这两个语句都是非法的,因此您会收到两个错误:

  • 如果val没有显式类型注释或_扩展,则无法将方法分配给- 请参阅下文)
  • 你不能重新分配val(如果你想知道,这$ires6是valREPL引入的新内容)

如果我在声明g中使用val而不是var,它们是否相同?如果没有,那么有什么区别呢?

区别在于val不能重新分配(即它是一个常量引用),而varcan(即它是一个可变引用).

有关此主题的更多信息:Scala中var和val定义之间的区别是什么?

它是什么意思(x:Int)Int与Int => Int =?相同?如果是这样,是否有一些情况我们应该优先于另一方?

方法和函数不尽相同,尽管编译器通过称为eta-expansion的转换尽力让您相信它们.在某些情况下,这种转换可以自动执行,在某些其他情况下,您需要明确并通过尾随触发它_.

在您的特定示例中(传递期望函数的方法),可以自动执行扩展.

您可以阅读此Q/A,以便更深入地讨论更喜欢哪种风格.

为什么会这样?Scala中_(下划线)的用法是什么?

下划线(_)在scala中有很多用途,其中一个是我之前提到过的,即触发方法的eta扩展到函数中.

这是方法的特殊语法,因此您根本无法将其应用于函数,因为它没有任何意义.

这就是为什么你可以做f _(这将把f方法变成一个函数),但你做不到g _(因为g它已经是一个函数).