在Scala中asInstanceOf 和(o:T)有什么区别?

我看到有两种方法在Scala中投射一个对象:

foo.asInstanceOf[Bar] (foo: Bar) 

当我尝试,我发现asInstanceOf不使用隐式转换,而另一个。

这两种方法之间有什么不同? 在哪里推荐使用一个呢?

  • foo.asInstanceOf[Bar]是一个types转换,主要是一个运行时操作。 它说,应该强制编译器认为foo是一个Bar 。 这可能会导致一个错误(一个ClassCastException ),如果当在运行时foo被评估为除了一个Bar之外的东西。

  • foo:Bar是一个types归属 ,它完全是编译时的操作。 这是让编译器帮助理解你的代码的含义,而不是强迫它相信任何可能是不真实的; 使用types归属不会导致运行时失败。

types归属也可以用来触发隐式转换。 例如,你可以定义下面的隐式转换:

 implicit def foo(s:String):Int = s.length 

然后确保它的使用像这样:

 scala> "hi":Int res29: Int = 2 

Inttypes赋值给String通常是一个编译时types错误,但在放弃编译器之前,将search可用的隐式转换以使问题消失。 将在编译时知道将在给定上下文中使用的特定隐式转换。

不用说,运行时错误是不可取的,所以你可以以types安全的方式(不使用asInstanceof )指定事物的程度越好越好! 如果您发现自己使用asInstanceOf ,则应该使用match来代替。

Pelotom的答案涵盖了相当不错的理论,下面是一些例子,使其更清晰:

 def foo(x: Any) { println("any") } def foo(x: String) { println("string") } def main(args: Array[String]) { val a: Any = new Object val s = "string" foo(a) // any foo(s) // string foo(s: Any) // any foo(a.asInstanceOf[String]) // compiles, but ClassCastException during runtime foo(a: String) // does not compile, type mismatch } 

正如你所看到的types归属可以用来解决歧义。 有时它们可​​能是编译器无法parsing的(请参阅后面的内容),它将报告一个错误,您必须解决它。 在其他情况下(如在示例中),它只是使用“错误”的方法,而不是你想要的。 foo(a: String)不会编译,表明types归属不是一个强制转换。 将它和上一行(编译器很高兴)相比较,但是你得到一个exception,所以错误被检测到,然后是types归属。

如果你也添加一个方法,你会得到一个无法解决的歧义

 def foo(xs: Any*) { println("vararg") } 

在这种情况下,foo的第一个和第三个调用将不会被编译,因为编译器无法决定是否要使用单个Any参数或可变参数调用foo,因为它们两个似乎都是同样好的。必须使用types归类来帮助编译器。

编辑另请参见Scala中types归属的目的是什么?

“Scala编程”在第15章 – “案例类和模式匹配”中详细介绍了这一点。

基本上,第二种forms可以在模式匹配中用作“types模式”,赋予isInstanceOf和asInstanceOffunction。 比较

 if (x.isInstanceOf[String]) { val s = x.asInstanceOf[String] s.length } else ... 

 def checkFoo(x: Any) = x match { case s: String => s.length case m: Int => m case _ => 0 } 

作者暗示,isInstance *做事方式的冗长是有意将您引入模式匹配风格的。

我不确定哪个模式对于没有testing的简单types转换更有效。

有一个差别的例子:

  1. types转换(asInstanceOf)是具有潜在运行时exception的运行时操作。
  2. 归属基本上只是在编译时进行的上传。

例:

 class Parent() { def method() {} } class Child1 extends Parent() { def method1() {} } class Child2 extends Parent() { def method2() {} } // we return Parent type def getChild1() : Parent = new Child1() def getChild2() : Parent = new Child2() def getChild() : Child1 = new Child1() (getChild1().asInstanceOf[Child1]).method1() // OK (getChild1().asInstanceOf[Child2]).method2() // runtime ClassCastException (getChild1() : Child2).method2() // compile-time error (getChild2() : Child2).method2() // compile-time error (getChild() : Parent).method1() // compile-time error (getChild()).method() // OK // with asInstanceOf, we can cast to anything without compile-time error getChild1().asInstanceOf[String] // runtime ClassCastException getChild1().asInstanceOf[Int] // runtime ClassCastException 

我们也可以使用multiple-dispatch调用方法:

 def prt(p: Parent) = println("parent") def prt(ch: Child1) = println("child") prt(new Parent()) // prints "parent" prt((new Child1()) : Parent) // prints "parent" prt(new Child1()) // prints "child" prt(new Parent().asInstanceOf[Child1]) // runtime ClassCastException prt(new Child1().asInstanceOf[Parent]) // prints "parent" 

我们可以定义隐式转换:

 // after definition of implicit conversions implicit def toChild1(p: Parent) : Child1 = new Child1() implicit def toChild2(p: Parent) : Child2 = new Child2() (getChild1() : Child2).method2() // OK - implicit conversion to Child2 in ascription (getChild2() : Child2).method2() // OK - implicit conversion to Child2 in ascription (getChild2()).method1() // OK - implicit conversion to Child1 when calling method1() (getChild2()).method2() // OK - implicit conversion to Child2 when calling method2() (getChild2() : Parent).method() // OK - no implicit conversion (getChild() : Parent).method1() // OK - implicit conversion to Child1 when calling method() getChild1().asInstanceOf[Int] // still runtime ClassCastException (no implicit conversion)