Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala中[T]和(o:T)的安装有什么区别?_Scala_Casting - Fatal编程技术网

Scala中[T]和(o:T)的安装有什么区别?

Scala中[T]和(o:T)的安装有什么区别?,scala,casting,Scala,Casting,我看到有两种方法可以在Scala中强制转换对象: foo.asInstanceOf[Bar] (foo: Bar) 当我尝试时,我发现asInstanceOf不使用隐式转换,而另一个使用隐式转换 这两种方法在行为上有什么不同?建议在何处使用一个而不是另一个?在Scala中编程在中详细介绍了这一点 基本上,第二种形式可以在模式匹配中使用,提供了isInstanceOf和asInstanceOf功能。比较 if (x.isInstanceOf[String]) { val s = x.asIn

我看到有两种方法可以在Scala中强制转换对象:

foo.asInstanceOf[Bar]
(foo: Bar)
当我尝试时,我发现
asInstanceOf
不使用隐式转换,而另一个使用隐式转换


这两种方法在行为上有什么不同?建议在何处使用一个而不是另一个?

在Scala中编程在中详细介绍了这一点

基本上,第二种形式可以在模式匹配中使用,提供了
isInstanceOf
asInstanceOf
功能。比较

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

作者暗示,
isInstance*
这种冗长的做事方式是有意将您推进模式匹配风格的

但是,我不确定哪种模式对于没有测试的简单类型转换更有效。

  • foo.asInstanceOf[Bar]
    是一种类型cast,主要是一种运行时操作。它说应该强迫编译器相信
    foo
    是一个
    Bar
    。如果在运行时将
    foo
    评估为非
    条形图
    ,则这可能会导致错误(一个
    ClassCastException

  • foo:Bar
    是一种类型归属,它完全是一种编译时操作。这有助于编译器理解代码的含义,而不会强迫它相信任何可能不真实的东西;使用类型属性不会导致运行时失败

类型归属也可用于触发隐式转换。例如,您可以定义以下隐式转换:

implicit def foo(s:String):Int = s.length
// 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)
然后确保其使用如下:

scala> "hi":Int                                 
res29: Int = 2
将类型
Int
归因于
String
通常是编译时类型错误,但在放弃之前,编译器将搜索可用的隐式转换以解决问题。将在给定上下文中使用的特定隐式转换在编译时已知


不用说,运行时错误是不受欢迎的,因此以类型安全的方式(不使用
asInstanceof
)指定内容的程度越好!如果你发现自己在使用
来代替
,那么你可能应该使用
匹配

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
}
如您所见,类型归属可用于解决歧义。有时,编译器无法解决这些问题(请参阅下文),编译器将报告错误,您必须解决它。在其他情况下(如示例中),它只是使用了“错误”的方法,而不是您想要的方法
foo(a:String)
未编译,表明类型归属不是强制转换。将其与前一行进行比较,在前一行中,编译器很高兴,但您得到了一个异常,因此将使用类型归属来检测错误

如果您还添加了一个方法,您将得到一个无法解决的歧义

def foo(xs: Any*) {
  println("vararg")
}
在这种情况下,foo的第一次和第三次调用将不会编译,因为编译器无法决定是使用单个Any参数调用foo,还是使用varargs调用foo,因为它们似乎都一样好=>必须使用类型归属来帮助编译器


编辑另请参见

有一个差异示例:

  • 类型转换(asInstanceOf)是一个运行时操作,可能存在运行时异常
  • 基本上只是在编译时执行的向上转换 例如:

    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
    
    我们也可以使用多重分派调用方法:

    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"
    
    我们可以定义隐式转换:

    implicit def foo(s:String):Int = s.length
    
    // 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)
    

    需要类型注释的一种情况是,当您想为null指定类型时,例如在使用JavaAPI时。感谢您的精彩解释@佩洛特:嘿,你的例子太棒了!“嗨”:国际。。。我从未见过或使用过这种方式,但这确实是一件有趣的事情。
    foo:Bar
    被称为类型归属。最好使用这个术语,因为它可以更容易地找到有关它的更多信息。或在搜索时查找此答案。:-)+1至Daniel,用于术语类型归属。否则我不会知道的