scala隐式参数类型推断

时间:2014-12-02 02:02:30

标签: scala

在scala 2.10.4下运行以下脚本。我期待a.classOp的结果应该是MyPage。为什么没什么?

scala> trait PageModel {
 | def classOp[T](implicit manifest: Manifest[T]) {
 |  println("Class: " + manifest.runtimeClass.getName)
 | }
 | }
defined trait PageModel

scala> class MyPage extends PageModel
defined class MyPage

scala> val a = new MyPage
a: MyPage = MyPage@1f2f992

scala> a.classOp
Class: scala.runtime.Nothing$

编辑:

我想我得到了答案。谢谢! 但是,在2.9.3上运行的相同代码给我一个java.lang.Object非常有趣。它应该表现如何吗?我在2.9.3中也看到了NoManifest。

scala> trait PageModel{
 |  def classOp[T](implicit m: Manifest[T]) {
 |    println("Class: " + manifest[T].erasure.getName)
 |  }
 | }
defined trait PageModel

scala> class MyPage extends PageModel
defined class MyPage

scala> val a = new MyPage
a: MyPage = MyPage@f7bf869

scala> a.classOp
Class: java.lang.Object

2 个答案:

答案 0 :(得分:4)

定义此方法def classOp[T](...)T约束的是什么?它本质上可以是任何内容,因此您要求T类型的隐式清单可以是任何内容:implicit manifest: Manifest[T]

如果查看scala.Predef,您可以看到以下声明:

val NoManifest = scala.reflect.NoManifest

NoManifest的位置:

object NoManifest extends OptManifest[Nothing]

OptManifest在哪里:

/** A `OptManifest[T]` is an optional [[scala.reflect.Manifest]].
 *  It is either a `Manifest` or the value `NoManifest`.

那么这一切转化为什么?

由于Nothing是所有类型的子类型,并且范围内始终有Manifest[Nothing]Predef始终在范围内),这意味着在没有其他任何内容时会注入此隐式找到了。


有了这个说法,我同意瑞恩的意见,你可能会这样做:

trait PageModel[T] {
 def classOp(implicit manifest: Manifest[T]) {
   println("Class: " + manifest.runtimeClass.getName)
 }
}

答案 1 :(得分:1)

我认为您打算在其子类上参数化PageModel,因为现在a.classOp没有任何内容可以填充T,因此编译器会使用底部类型{ {1}}。

例如:

Nothing

我假设您希望获得scala> a.classOp[String] java.lang.String 的班级名称。在这种情况下,您需要在其子类型上参数化MyPage

PageModel

显然,在REPL trait PageModel[T] { def classOp(implicit manifest: Manifest[T]) = println("Class: " + manifest.runtimeClass.getName) } class MyPage extends PageModel[MyPage] val a = new MyPage a.classOp // prints "Class: $line11.$read$$iw$$iw$MyPageModel" 之外会打印出更易读的FQCN。