Functions without arguments, with unit as argument in scala
def foo(x: Int, f: Unit => Int) = println(f())
foo(2, { Unit => 3 + 开发者_运维技巧4 })
// case 1
def loop: Int = 7
foo(2, loop) // does not compile
changing loop to
// case 2
def loop(): Int = 7
foo(2, loop) // does not compile
changing loop to
// case 3
def loop(x: Unit): Int = 7 // changing according to Don's Comments
foo(2, loop) // compiles and works fine
Shouldn't case 1
and case 2
also work? Why are they not working?
Defining foo as
def foo(x: Int, y: () => Int)
then case 2
works but not case 1
.
Arent they all supposed to work, defining the functions either way?
Also I think () => Int
in foo is a bad style, y:=> Int
does not work. Comments?
Scala distinguishes between the following things:
- Functions/methods with no parameter lists ("by-name parameter" if a function)
- Functions with one empty parameter list
- Functions with one parameter of type Unit
None of these are equivalent, although as a convenience Scala allows you to elide empty parameter lists. (Incidentally, two empty parameter lists are also not the same.)
So, even though Unit
is written ()
, this is not the same as the function argument parens ()
for a function or method. Instead, think of ()
as a Tuple0
.
So, if you say f: Unit => Int
, what you mean is "f takes one parameter, but it's a really boring parameter because it is Unit
, which must always be the same boring Tuple0
value ()
". What you're writing is really short for f: (Unit) => Int
.
If you say f: () => Int
, then you mean that "f takes no parameters and produces an Int
".
If you say f: => Int
, then you mean that "delay the execution of whatever statement produces an Int
value until we use it in this code (and re-evaluate it each time)". Functionally, this ends up being basically the same as f: () => Int
(and internally is converted into the same Function0
class), but it has a different usage, presumably to allow for a more compact form of closures (you always omit the =>
in the calling code).
()=>Int is Function0[Int] while Unit=>Int is Function1[Unit,Int]
scala> val function0: () => Int = () => 5
function0: () => Int = <function0>
scala> val function1: Unit => Int = u => 5
function1: (Unit) => Int = <function1>
scala> function0()
res0: Int = 5
scala> function1("anything")
res1: Int = 5
scala> function1(100)
res2: Int = 5
scala>
Also note that () is an object of Unit
scala> function1(())
res11: Int = 5
scala> function1 ()
res12: Int = 5
scala> function1()
res13: Int = 5
scala> val unit = ()
unit: Unit = ()
scala> function1(unit)
res15: Int = 5
scala> function1 apply unit
res16: Int = 5
scala>
In case 1 and 2 above, the return value of loop rather than loop itself is type checked for the second argument to foo and fails: Int != Unit => Int
The change to loop has a typo.
精彩评论