Параметр конструктора вызова по имени в неявном классе
Следующий код не компилируется. Желательно иметь параметр конструктора call-by-name в неявном классе, как показано здесь,
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)
}
}
где звонок
val (res, time) = f(3).elapsed
res: Int = 6
time: Double = 123.0
Эта ошибка сообщается в REPL,
<console>:1: error: `val' parameters may not be call-by-name
implicit class RichElapsed[A](val f: => A) extends AnyVal {
Таким образом, чтобы спросить, как RichElapsed
класс может быть реорганизован.
Заранее спасибо.
2 ответа
Решение Питера Шмитца просто отбросить val
(вместе с надеждой на поворот RichElapsed
в класс значения), безусловно, самая простая и наименее навязчивая вещь, чтобы сделать.
Если вы действительно чувствуете, что вам нужен класс значений, другая альтернатива это:
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 )
Обратите внимание, что при использовании класса значений, как указано выше, можно удалить экземпляр временного RichElapsed
Например, все еще продолжается некоторая упаковка (как с моим решением, так и с решением Питера Шмитца). А именно, тело передано по имени как f
заключен в экземпляр функции (в случае Питера Шмитца это не проявляется в коде, но все равно произойдет под капотом). Если вы хотите удалить эту упаковку, я думаю, что единственным решением будет использование макроса.
Сделать это без val
как требует сообщения об ошибках, а затем вы также должны отказаться от AnyVal
поскольку у класса значений должен быть ровно один публичный val:
implicit class RichElapsed[A](f: => A)