在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
答案 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。