考虑以下Scala代码
def NOTImplementedIn[T<: AnyRef](t:T):String =
throw new Exception(t.getClass.getName+": Input type not implemented")
def NOTImplementedOut[T<: AnyRef](s:String):T =
throw new Exception("Output type not implemented")
在第一种情况下,可以推断输入类型T
。有没有办法在第二种情况下推断输出类型T
?我想在例外中包含类型名称。
答案 0 :(得分:4)
始终会推断T
的下限类型。如果没有明确给出下限类型绑定,则Nothing是绑定。
这个推论是正确的。由于通用参数类型会被删除为运行时,因此在运行时对f[String]("foo")
,f[File]("foo")
和f[List[Int]]("foo")
以及f[Nothing]("foo")
的调用是相同的调用f("foo")
。结果必须是有效的String
,File
,List[Int]
和Nothing
。成为Nothing
是满足它的唯一方法(这意味着没有结果)。如果有一个更强的低级类型绑定,它只需要是那种类型。
这样做的结果是,f[T >: LowerBound](parameters): T,
中未显示T
的例行parameters
与f(parameters): LowerBound
没有区别,并且没有任何意义它是通用的(当LowerBound
没有明确说明时,绑定是类型Nothing
)
与运行时调用f[T]("foo")
仅为f("foo")
的想法相同,很明显,该名称不会出现在异常消息中。因此,T
必须在运行时通过,并且清单是正常的方法,如Dave所述。现在,T
确实出现在参数中,并且一切都不同。如果有人调用f[File]("foo")
,编译器会将其转换为f("foo")(manifest_of_file)
,其中manifest_of_file
允许获取类型File的名称。
这仍然没有推论,因为File
已被明确写出。可以推断类型T
的唯一方法是从上下文中对f
的预期调用类型。如果一个人val file: File = f("foo")
,或者将f("foo")
类型的参数值传递给某个例程,或者只是写f("foo"): File
,那么File
会被推断出来吗?不,它不会。再次推断Nothing
。原因是它比File更精确,因为编译器可以传递Manifest [File]或Manifest [Nothing](以及其间的任何类型),它选择更精确的类型。对于Nothing
,这可能会令人惊讶,但是假设您的下限类型为String
,而预期的类型只是AnyRef
,没有明显的理由选择AnyRef而不是更好的String 。
def f[T >: String : Manifest](s: String): T = "type is " + manifest[T].toString
val x: AnyRef = f("foo"): AnyRef
x: Anyref = type is java.lang.String
与您的示例相同,Nothing
作为较低的类型绑定:
def g[T: Manifest](s: String): T = throw new Exception("type is " + manifest[T])
val y: String = g("foo"): String
java.lang.Exception: type is Nothing
at .g(<console>:7)
....
答案 1 :(得分:3)
是的,使用Manifest
。
def NOTImplementedOut[T<: AnyRef](s:String)(implicit m: scala.reflect.Manifest[T]):T =
throw new Exception(m.toString + ": Output type not implemented")