在 Scala 中,如果泛型方法的调用者省略了显式指定类型参数,那么糟糕的事情就会大打折扣。例如:
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]
}
Run Code Online (Sandbox Code Playgroud)
我应该为makey()(eg makey[Boolean]())提供一个类型参数,但是在这种情况下我忘记了程序已编译(顺便说一下,这非常容易做到)。
该程序最终将失败needsBool(省略了实现),它没有接收到一个Expression[Booolean]对象 - 它反而得到了一个Expression[Nothing]对象。Scala 的文档说 Nothing 是所有类型的子类,这看起来异常粗鲁,并且无论出现在哪里都肯定会破坏类型安全。
所以,为了重新引入一些类型安全,我可以:
makey返回 Expression[Nothing] 但要求提供类型参数?(我怀疑不是),或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]
}
Run Code Online (Sandbox Code Playgroud)
我找到了一个有点hacky的解决方案,但它有效。创建一个NotNothing在其类型参数中逆变的类型,然后为Any和提供一个隐式对象Nothing。现在,如果您尝试使用的值NotNothing与Nothing编译器会抱怨歧义。案例:
sealed trait NotNothing[-T]
object NotNothing {
implicit object YoureSupposedToSupplyAType extends NotNothing[Nothing]
implicit object notNothing extends NotNothing[Any]
}
Run Code Online (Sandbox Code Playgroud)
然后makey使用以下NotNothing类型约束您的函数:
def makey[T : NotNothing]() = { ... }
Run Code Online (Sandbox Code Playgroud)
瞧,现在如果你忘记提供一个类型,你会得到一个编译时错误!
| 归档时间: |
|
| 查看次数: |
1077 次 |
| 最近记录: |