【问题标题】:Scala call-by-name constructor parameter in implicit class隐式类中的Scala按名称调用构造函数参数
【发布时间】:2014-04-16 20:48:49
【问题描述】:

以下代码无法编译。希望在隐式类中有一个按名称调用的构造函数参数,如此处所示,

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类如何重构。

提前致谢。

【问题讨论】:

    标签: scala implicit callbyname


    【解决方案1】:

    Peter Schmitz 的解决方案是简单地删除 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 实例的实例化,但仍有一些包装正在进行(无论是我的解决方案还是 Peter Schmitz 的解决方案)。 也就是说,通过名称传递的主体 f 被包装到一个函数实例中(在 Peter Schmitz 的情况下,这在代码中并不明显,但无论如何都会在引擎盖下发生)。 如果您也想删除此包装,我相信唯一的解决方案是使用宏。

    【讨论】:

    • 非常感谢,被选为澄清观察的首选答案。
    【解决方案2】:

    按照错误消息的要求,不要使用val,然后您还必须放弃AnyVal,因为值类需要恰好有一个公共val:

    implicit class RichElapsed[A](f: => A)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      • 1970-01-01
      • 1970-01-01
      • 2011-04-15
      • 2016-03-12
      相关资源
      最近更新 更多