class X[A](val value: A){
def unapply[B <: A](x: X[B]) = true
}
object Main extends App {
val int = new X(1)
val string = new X("a")
val pf: PartialFunction[Any, Int] = { case o @ int() => o.value }
println(pf(string) + 1)
}
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:105)
我认为此代码应该抛出 scalac应警告此代码。MatchError
而不是ClassCastException
。或者
Scala 2.11.5
编辑:
Scala 2.9.3警告如下。但不是2.10,2.11
Main.scala:8: warning: non variable type-argument B in type pattern X[B] is unchecked since it is eliminated by erasure
val pf: PartialFunction[Any, Int] = { case o @ int() => o.value }
^
我从一开始就理解类型擦除。
换句话说,pf.isDefinedAt(string)
返回true,pf.apply(string)
抛出ClassCastException
Welcome to Scala version 2.11.5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_67).
Type in expressions to have them evaluated.
Type :help for more information.
scala> :paste
// Entering paste mode (ctrl-D to finish)
class X[A](val value: A){
def unapply[B <: A](x: X[B]) = true
}
val int = new X(1)
val string = new X("a")
val pf: PartialFunction[Any, Int] = { case o @ int() => o.value }
// Exiting paste mode, now interpreting.
defined class X
int: X[Int] = X@4f3cb3fc
string: X[String] = X@1a4c8e08
pf: PartialFunction[Any,Int] = <function1>
scala> pf.isDefinedAt(string)
res0: Boolean = true
scala> pf.apply(string)
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
at scala.runtime.BoxesRunTime.unboxToInt(BoxesRunTime.java:105)
... 33 elided
答案 0 :(得分:0)
他们竭尽全力:
scala> import reflect._
import reflect._
scala> class X[A: ClassTag](val v: A) { def unapply[B <: A](x: X[B]) = x.v match {
| case _: A => true
| case _ => false } }
defined class X
scala> val int = new X(1)
int: X[Int] = X@2a5ca609
scala> val s = new X("a")
s: X[String] = X@4667ae56
scala> val pf: PartialFunction[Any, Int] = { case o @ int() => o.v }
pf: PartialFunction[Any,Int] = <function1>
scala> pf(s)
scala.MatchError: X@4667ae56 (of class X)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:253)
at scala.PartialFunction$$anon$1.apply(PartialFunction.scala:251)
at $anonfun$1.applyOrElse(<console>:12)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:36)
... 33 elided
scala> pf(int)
res1: Int = 1
但我想你的意思是,如果他们静静地抱怨这个,为什么他们不为我插入一个测试实例呢?至少他们什么时候可以?
scala> val pf: PartialFunction[X[_], Int] = { case o @ int() => o.v }
<console>:12: error: inferred type arguments [_$1] do not conform to method unapply's type parameter bounds [B <: Int]
val pf: PartialFunction[X[_], Int] = { case o @ int() => o.v }
^
<console>:12: error: type mismatch;
found : _1
required: Int
val pf: PartialFunction[X[_], Int] = { case o @ int() => o.v }
^
答案 1 :(得分:0)
使用Any
是代码中的一大气味。当你丢弃你的类型信息时,你就不会对编译器造成错误。
首先,我将Any
替换为X[C]
:
def pf[C]: PartialFunction[X[C], Int] = { case o @ int() => o.value }
这会产生以下编译错误:
[error] Foo.scala:12: inferred type arguments [C] do not conform to method unapply's type parameter bounds [B <: Int]
[error] def pf[C]: PartialFunction[X[C], Int] = { case o @ int() => o.value }
[error] ^
如果要将类型检查延迟到运行时,则需要在某处捕获类型信息。我们可以在X
中执行此操作,如下所示:
import scala.reflect.runtime.universe._
class X[A: TypeTag](val value: A) {
val typeTag = typeOf[A]
def unapply[B](x: X[B]): Boolean =
x.typeTag <:< this.typeTag
}
现在我们必须告诉编译器,如果匹配成功C
实际上是Int
。
def pf[C]: PartialFunction[X[C], Int] = { case o @ int() => o.value.asInstanceOf[Int] }
println(pf(int) + 1)
println(pf(string) + 1)
这似乎有效:
[info] Running Main
2
[error] (run-main-7) scala.MatchError: X@1c34aaaa (of class X)
scala.MatchError: X@1c34aaaa (of class X)