问题
The following code does not compile. Desired is to have a call-by-name constructor parameter in an implicit class as illustrated here,
def f(n: Int) = (1 to n) product
implicit class RichElapsed[A](val f: => A) extends AnyVal {
def elapsed(): (A, Double) = {
val start = System.nanoTime()
val res = f
val end = System.nanoTime()
(res, (end-start)/1e6)
}
}
where a call
val (res, time) = f(3).elapsed
res: Int = 6
time: Double = 123.0
This error is reported in REPL,
<console>:1: error: `val' parameters may not be call-by-name
implicit class RichElapsed[A](val f: => A) extends AnyVal {
Thus to ask how RichElapsed
class could be refactored.
Thanks in Advance.
回答1:
Peter Schmitz's solution to simply drop the val
(along with the hope of turning RichElapsed
into a value class) is certainly the simplest and least intrusive thing to do.
If you really feel like you need a value class, another alternative is this:
class RichElapsed[A](val f: () => A) extends AnyVal {
def elapsed(): (A, Double) = {
val start = System.nanoTime()
val res = f()
val end = System.nanoTime()
(res, (end-start)/1e6)
}
}
implicit def toRichElapsed[A]( f: => A ) = new RichElapsed[A](() => f )
Note that while using a value class as above allows to remove the instantiation of a temporary RichElapsed
instance, there is still some wrapping going on (both with my solution and with Peter Schmitz's solution).
Namely, the body passed by name as f
is wrapped into a function instance (in Peter Schmitz's case this is not apparent in the code but will happen anyway under the hood).
If you want to remove this wrapping too, I believe the only solution would be to use a macro.
回答2:
Do it without val
as the error messages demands and then you also have to abandon the AnyVal
since a value class needs to have exactly one public val:
implicit class RichElapsed[A](f: => A)
来源:https://stackoverflow.com/questions/23103947/scala-call-by-name-constructor-parameter-in-implicit-class