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

时间:2015-01-17 01:03:55

标签: scala

我在Scala中声明一个函数时试图找出defvar/val之间的区别。

假设我们有一个功能:

scala> def f(x: Int) = { x * 2 }
f: (x: Int)Int

另一个功能g:

scala> var g = (x:Int) => x*2
g: Int => Int = <function1>

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

scala> f(2)
res0: Int = 4

scala> g(2)
res1: Int = 4

然而,我可以做到

g = f
g: Int => Int = <function1>

但不是

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
         ^

问题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

问题3 :这是否意味着(x: Int)IntInt => Int = <function1>相同?如果是这样,是否有一些情况我们应该支持一个而不是另一个?

事情正在与_(下划线),

联系起来
scala> three(f _)
res49: Int = 6

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

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

1 个答案:

答案 0 :(得分:6)

  

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

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

然后解析器会感到困惑,并最终通过将作业f = g解释为

来尝试保存这一天。
val $ires6 = f
f = g

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

  • 如果没有明确的类型注释或val扩展,您无法为_分配方法 - 请参阅下文)
  • 您无法重新分配val(如果您想知道,$ires6是REPL引入的新val
  

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

区别在于val无法重新分配(即它是一个常量引用),而var可以(即它是一个可变引用)。

有关此主题的更多信息,请访问:What is the difference between a var and val definition in Scala?

  

是否意味着(x:Int)Int与Int =&gt;相同Int =?如果是这样,是否有一些情况我们应该支持一个而不是另一个?

Methods and functions are not the same,虽然编译器通过称为eta-expansion的转换尽力让你相信它们。在某些情况下,这种转换可以自动执行,在其他一些情况下,您需要明确并使用尾随_触发它。

在您的具体示例中(传递预期函数的方法),可以自动执行扩展。

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

  

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

下划线(_has many uses in scala,其中一个是我之前提到的那个,即触发方法的eta扩展为函数。

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

这就是为什么你可以f _(将f方法转换为函数)的原因,但是你不能g _(从{{1}开始g 1}}它已经是一个功能了。)