2014-12-02 151 views
0

在scala 2.10.4下运行以下脚本。我期待a.classOp的结果应该是MyPage。为什么没有?scala隐式参数类型推断

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 = [email protected] 

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 = [email protected] 

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

回答

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总是在范围内)这将意味着在没有其他发现这个隐将被注入。


与此说,我同意Ryan和你大概的意思做:

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

感谢您的回答! – 2014-12-02 21:04:10

1

我想你的意思是参数上它的子类PageModel,因为现在a.classOp没有任何东西T与这样编译器无二底式,Nothing填补。

例如:

scala> a.classOp[String] 
java.lang.String 

我假设你希望得到的MyPage类名。在这种情况下,你需要在它的子类型参数PageModel

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" 

显然REPL classOp外面会打印出更可读FQCN。

+0

感谢您的回答! – 2014-12-02 21:04:27