我在我的代码中广泛使用scala的2.10 TypeTag,我观察到一些与我不理解的类型推断相关的行为。
示例代码:
import scala.reflect.runtime.universe._
object BugDemo extends App {
def printType[T <: AnyRef : TypeTag]() : T = {
println(typeOf[T]);
null.asInstanceOf[T];
}
case class Foo()
var foo1 = printType[Foo]()
var foo2 : Foo = printType[Foo]()
var foo3 : Foo = printType()
}
现在我希望它打印Foo
3次,但实际上我得到了(scala 2.10.3):
BugDemo.Foo
BugDemo.Foo
Nothing
我的代码出了什么问题?为什么scala不想为T
中的foo3
传递正确的类型标记?
答案 0 :(得分:3)
这没有错。
如果未指定type参数,则scala编译器采用最具体的类型。如果printType()
为Nothing
(scala类型层次结构中的底部类型)。
由于Nothing
是Foo
的子类型,因此您的代码有效:
var foo3 : Foo = printType[Nothing]()
有趣的是,使用var foo3 : Nothing = printType[Nothing]()
或printType[Nothing]()
,您将获得NullPointerException
:
scala> var foo3 : Nothing = printType[Nothing]()
Nothing
java.lang.NullPointerException
scala> printType[Nothing]()
Nothing
java.lang.NullPointerException
您无法获取Nothing
的实例,但您的代码(var foo3 : Foo = printType[Nothing]()
)因类型擦除而有效。它看起来像一个无法修复的scala bug。
答案 1 :(得分:0)
当调用者没有明确提供scala时,scala推断出的类型参数不是什么。我讨厌(HATE)这种默认行为,因为它会导致各种运行时错误。所有内容都不允许参数。
最好强制在requiring that its not Nothing编译时完全指定type参数:
sealed trait NotNothing[-T]
object NotNothing {
implicit object YoureSupposedToSupplyAType extends NotNothing[Nothing]
implicit object notNothing extends NotNothing[Any]
}
然后:
def printType[T : TypeTag : NotNothing]() : T = { ... }