在scala中,如果泛型方法的调用者省略显式指定类型参数,那么shit可以命中风扇。例如:
class Expression[+T] // Will have eval():T method, so +T
class NothingTest {
def makey[T](): Expression[T] = null
def needsBool(b: Expression[Boolean]): Unit = {}
var b: Expression[Boolean] = null
var n = makey() // : Expression[Nothing]
b=n // Yikes.
needsBool(n) // :-/ Supplied Expression[Nothing] ... not a Expression[Nothing]
}
我假设为makey()
提供了一个类型参数(例如makey[Boolean]()
),但是在这个例子中我忘记了,程序编译了(通过这样,很容易做到。)
程序最终将失败needsBool
(实现省略),但没有收到Expression[Booolean]
个对象 - 它改为Expression[Nothing]
个对象。 Scala的文档说没有什么是所有类型的子类,这看起来格外粗鲁,并且肯定会在任何地方打破类型安全。
所以,为了重新引入一些类型安全性,我可以:
makey
返回Expression [Nothing],但要求提供类型参数? (I suspect not),或者needsBool
收到表达式[Nothing]?在编译时。
更新
更全面(编译,但运行时失败的示例):
class Expression[+T](val value:T){
def eval:T = value
}
class NothingTest {
def makey[T](): Expression[T] = new Expression[String]("blah").asInstanceOf[Expression[T]]
def needsBool(b: Expression[Boolean]): Unit = {
val boolval = b.eval // Explode! String is not a Boolean
println(boolval)
}
var b: Expression[Boolean] = null
var n = makey() // : Expression[Nothing]. You're suppose to supply a type, but forgot.
b=n // Yikes.
needsBool(n) // :-/ Supplied Expression[Nothing]
}
答案 0 :(得分:4)
我发现了一个有点hacky的解决方案,但它确实有效。
创建一个在其类型参数中具有逆变的NotNothing
类型,然后为Any
和Nothing
提供隐式对象。
现在,如果您尝试将NotNothing
的值与Nothing
一起使用,编译器将会抱怨模糊性。一个很好的例子:
sealed trait NotNothing[-T]
object NotNothing {
implicit object YoureSupposedToSupplyAType extends NotNothing[Nothing]
implicit object notNothing extends NotNothing[Any]
}
然后使用makey
类型约束您的NotNothing
函数:
def makey[T : NotNothing]() = { ... }
现在,如果您忘记提供类型,您将收到编译时错误!