问题
From book 'Programming in Scala':
var assertionsEnabled = true
def myAssert(predicate: () => Boolean) =
if (assertionsEnabled && !predicate())
throw new AssertionError
myAssert(() => 5 > 3)
Using empty parameter list is awkward. Scala provides by-name parameter to solve this.
def byNameAssert(predicate: => Boolean) =
if (assertionsEnabled && !predicate)
throw new AssertionError
byNameAssert(5 > 3)
I have a confusion in this discussion.myAssert takes in a parameter which is a function, which in turn takes no parameter and returns a boolean.
What is input type for byNameAssert?Is it same as myAssert?To me,it seems an expression which evaluates to a boolean value, and having it in by-name form means that expression is evaluated whenever it is called and not when being passed to byNameAssert.But then it is not same as input type of myAssert. And if that is the case, then byNameAssert and myAssert are quite different.
回答1:
To me,it seems an expression which evaluates to a boolean value, and having it in by-name form means that expression is evaluated whenever it is called and not when being passed to byNameAssert.
Yes. But the way it's implemented is that Scala compiles byNameAssert and myAssert to exactly the same code (except for different @ScalaSignature annotation) and whenever it sees calls like byNameAssert(5 > 3) they are rewritten so the next compiler stage sees the argument as () => 5 > 3 instead.
回答2:
What is input type for byNameAssert?
=> Boolean
Is it same as myAssert?
No, myAssert expects () => Boolean as argument. While "morally the same", it is treated as a separate type by the compiler.
The => Boolean-thing is neither () => Boolean, nor Boolean. The following little example is supposed to further illustrate that. Trying to assign curried foo to variables of type () => Boolean and Boolean fails:
scala> def foo(b: => Boolean): Unit = {}
foo: (b: => Boolean)Unit
scala> val f: Boolean => Unit = foo _
<console>:12: error: type mismatch;
found : (=> Boolean) => Unit
required: Boolean => Unit
val f: Boolean => Unit = foo _
^
scala> val f: (() => Boolean) => Unit = foo _
<console>:12: error: type mismatch;
found : (=> Boolean) => Unit
required: (() => Boolean) => Unit
val f: (() => Boolean) => Unit = foo _
^
But this works:
scala> val f: (=> Boolean) => Unit = foo _
f: (=> Boolean) => Unit = $$Lambda$1090/668948486@69bc9584
So, while => Boolean is essentially the same as () => Boolean from the point of view of the implementation, it is treated separately as a different type, and it behaves quite differently when it comes to syntactic desugaring of expressions and code blocks passed as arguments to functions.
来源:https://stackoverflow.com/questions/49707521/by-name-parameter-in-scala