我在Scala中声明一个函数时试图找出def
和var/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)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 _)
^
问题4 :为什么会这样? Scala中_
(下划线)的用法是什么?
答案 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}}它已经是一个功能了。)