我对以下Scala编译器行为很感兴趣。当我声明一个类型为单位的函数,但仍然提供一个求值为Int的函数时,Scala编译器就可以了。
def add(x:Int, y:Int) = x + y
def main(args: Array[String]): Unit = {add(args(0).toInt, args(0).toInt)}
虽然
中的其他类型也不是这样def afunc: String = {1} //type mismatch; found : Int(1) required: String
如果我写
def afunc: Unit = {1}
或
def main(args: Array[String]): Unit = {2 + 2} // Which is just like the first addition above
在这两种情况下,我都收到以下警告:
a pure expression does nothing in statement position; you may be omitting necessary parentheses
从某种意义上说,这里有两个问题。返回求值到Int的函数和表达式2 + 2之间的区别是什么呢?那么为什么在编程上,编译器不会抱怨假设要求为Unit的函数,得到一个评估为另一种类型的函数,因为它会在其他类型之间发生。
非常感谢,
Maatari
答案 0 :(得分:3)
返回评估的函数有什么区别 Int和表达式2 + 2.
评估为Int的函数可能有副作用
var a = 0
def fn: Int = {
a = a + 1
1
}
每次调用fn都会改变a的值。
那么为什么在地球上,编译器不会抱怨那个函数 假设评估单位,得到一个评估另一个的身体 类型,因为它会在其他类型之间发生。
当你指定Unit作为返回类型时,编译器会从函数返回Unit的任何值进行隐式转换(只有一个Unit值,因为它是一个对象,你可以把它想象为Scala的void类型)
答案 1 :(得分:1)
Unit
被推断为返回类型。例如,
scala> val h = new collection.mutable.HashMap[String,String]
h: scala.collection.mutable.HashMap[String,String] = Map()
scala> h += "fish" -> "salmon"
res1: h.type = Map(fish -> salmon)
我们看到可变+=
的{{1}}方法返回地图。
但如果你不推断单位,那么
HashMap
不起作用。
哪个更糟糕 - 意外地期望返回值与要求您明确返回最无聊的可能返回值 - 取决于您的代码的功能。如果你有不止一些副作用,不要推断def add(a: String, b: String): Unit = h += a -> b
是相当痛苦的。
答案 2 :(得分:1)
只有圆括号的函数主要用于副作用。它可能会返回一个结果,因为它在C或Java时代很常见,但实际上我们并不关心,因为我们不会使用它。 {} 等效于:Unit = ,返回类型的注释可以看作是强制转换或隐式转换,以匹配函数预期的类型。
这是另一个发生此行为的示例。
def add(a: Int, b:Int) : Double = a + b
add: (a: Int, b: Int)Double
scala> add(4,5)
res17: Double = 9.0
因此,似乎每个值都可以转换为单位。
scala> val a: Unit = 1:Unit
<console>:28: warning: a pure expression does nothing in statement position; you may be omitting necessary parentheses
val a: Unit = 1:Unit
^
a: Unit = ()