Can't put PartialFunction in scala class constructor

眉间皱痕 提交于 2019-12-10 13:59:01

问题


There appears to be a restriction that you can't use PartialFunction literals in class constructors:

scala> case class X(a: PartialFunction[Any, Any]) { def this() = this({case x => x}) }
<console>:7: error: Implementation restriction: <$anon: Any => Any> requires premature access to class X.
   case class X(a: PartialFunction[Any, Any]) { def this() = this({ case x => x}) }

My first question is why does a partial function literal need access to "this". My second question/observation is that in the Scala REPL, running the same code again crashes the REPL:

scala> case class X(a: PartialFunction[Any, Any]) { def this() = this({ case x => x}) }
java.lang.NullPointerException
    at scala.tools.nsc.Global$Run.compileLate(Global.scala:1595)
    at scala.tools.nsc.GlobalSymbolLoaders.compileLate(GlobalSymbolLoaders.scala:29)
    at scala.tools.nsc.symtab.SymbolLoaders$SourcefileLoader.doComplete(SymbolLoaders.scala:369)
    ...

And lastly, is there a good workaround for this issue?


回答1:


Your first question is answered in the comment section of this question

Quoting Imm:

Anonymous classes have access to their enclosing class. The compiler doesn't know that your anonymous partial function doesn't actually access anything (and it would be very hard to check this in full generality); it simply disallows creating any anonymous classes until you're into the class proper.

Why it crashes the REPL is a good question, you should probably submit a ticket to Typesafe with this code example.

A workaround is quite simple, just define the anonymous function outside of the class so the compiler knows the exact state you are closing over:

object X {
  val Default: PartialFunction[Any, Any] = { case x => x }
}

case class X(a: PartialFunction[Any, Any]) {
  def this() = this(X.Default)
}



回答2:


Your first question is answered in the comment section of this question.

The issue is that the compiler is too restrictive because it didn't know how to lift stuff out of the constructor parameter block.

The workaround is given in the other answer, which is what the compiler should be doing with that other stuff.

The other workaround is manual construction:

case class X(a: PartialFunction[Any, Any]) { def this() = this({
    class $anonfun extends runtime.AbstractPartialFunction[Any, Any] {
      override def applyOrElse[A, B >: Any](x: A, default: A => B): B = x match {
        case x => x
        //case _ => default(x) // completeness
      }
      override def isDefinedAt(x: Any) = x match {
        case x => true
        //case _ => false
      }
    }
    new $anonfun()
  })
}

The answer to your second question is that it is SI-9170, fixed for 2.11.7.



来源:https://stackoverflow.com/questions/30823381/cant-put-partialfunction-in-scala-class-constructor

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!