避免在通用方法中转换为Nothing

时间:2010-07-01 11:49:38

标签: generics scala

scala> def foo[U](t: Any) = t.asInstanceOf[U]
foo: [U](t: Any)U

scala> val s: String = foo("hi")

scala> val n = foo("hi")
java.lang.ClassCastException: java.lang.String cannot be cast to scala.runtime.Nothing$
    at .<init>(<console>:6)
    at .<clinit>(<console>)
    at RequestResult$.<init>(<console>:9)
    at RequestResult$.<clinit>(<console>)
    at RequestResult$scala_repl_result(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$18.apply(Interpreter.scala:981)
    at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$18.apply(Interpreter.scala:981)
    at scala.util.control.Exce...

有没有办法写#foo以便它返回Any如果'U'没有被推断或明确设置为“真实”类型?

4 个答案:

答案 0 :(得分:7)

没有。静态类型为U。如果将其推断为Nothing,则编译器将不允许返回值Any的值。

您可以改进运行时错误消息:

def foo[U: Manifest](t: Any): U = if (implicitly[Manifest[U]] == manifest[Nothing]) 
  error("type not provided") 
else t.asInstanceOf[U]

或遵循Arjan的建议。

答案 1 :(得分:2)

答案是您需要始终使用foo[String]("hi")指定泛型类型。由于泛型类型U未出现在任何参数中,因此无法推断出它。

无法推断foo的通用参数默认为Any(永远不会推断它永远不会被推断)。如果您要将该功能重新定义为

def foo[U](t:U)=t.asInstanceOf[U]

然后以下调用将无法编译:

val s:Any="Hi"
foo[String](s) 

答案 2 :(得分:2)

here更好地修复foo,以便无法调用它来返回Nothing类型:

sealed trait NotNothing[-T] 

object NotNothing {
  implicit object YoureSupposedToSupplyAType extends NotNothing[Nothing]
  implicit object notNothing extends NotNothing[Any] 
}

def foo[U:NotNothing](t:U)=t.asInstanceOf[U]

这样,如果您忘记添加type参数,您将收到编译时警告:

f("123")  // Fails
f[String]("123")  // OK

答案 3 :(得分:1)

我不确定这是不是你的意思,但你不能只用U作为t而不是Any的类型吗?


scala> def foo[U](t: U) = t.asInstanceOf[U]         
foo: [U](t: U)U

scala> foo("hi")
res0: java.lang.String = hi

scala> foo(1)   
res1: Int = 1

scala> val a:Any = "hi" 
a: Any = hi

scala> foo(a)
res2: Any = hi