2015-12-10 16 views
8

मैं this प्रश्न का उत्तर देने का प्रयास कर रहा था, जैसा कि मैंने सोचा था कि मुझे जवाब पता था। बाहर कर देता है, मैं काफी पर्याप्त नहीं पता था:कभी-कभी '.asInstanceOf` क्यों फेंकता है, और कभी-कभी नहीं?

class Inst[T] { 
    def is(x: Any) = scala.util.Try { as(x) }.isSuccess 
    def as(x: Any): T = x.asInstanceOf[T] 
} 

scala> new Inst[String].is(3) 
res17: Boolean = true 

scala> new Inst[String].as(3) 
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String 
... 33 elided 

यहाँ क्या हो रहा है:/

यहाँ एक परीक्षण मैंने किया है है? as पर केवल दूसरी कॉल क्यों फेंकती है, लेकिन पहले नहीं?

उत्तर

10

ऐसा इसलिए है क्योंकि क्लास-कास्ट-अपवाद केवल तभी फेंक दिया जाता है जब आप मूल्य के साथ कुछ करते हैं, कलाकार के बाद उस पर एक विधि कॉल करें। उदाहरण के लिए आरईपीएल में, आपके पास दूसरे मामले में toString कॉल होगा। नोट:

new Inst[String].as(3);()   // nothing happens 
new Inst[String].as(3).toString;() // exception 

कारण है कि इस लेता अतिरिक्त कदम है कि Inst[T] प्रकार पैरामीटर T जो रनटाइम पर मिटा दिया जाता है के साथ सामान्य है, केवल जब कॉल-साइट (जिसमें T प्रकार का स्थिर ज्ञान है) परिणाम पर एक विधि कॉल करने का प्रयास करता है, वास्तविक प्रकार की जांच होती है।


अपने अनुवर्ती प्रश्न के लिए, toString किसी भी वस्तु पर परिभाषित किया गया है और तब से T सामान्य है आप एक बॉक्स्ड पूर्णांक (<: AnyRef) और toString और printlnis विधि के भीतर सफल होने के लिए है। तो एक और उदाहरण है, जहां Try विफल हो जाएगा यह है:

class Inst[T] { 
    def foo(x: Any)(implicit ev: T <:< String) = scala.util.Try { 
    ev(as(x)).reverse 
    }.isSuccess 
} 

new Inst[String].foo(3) // false! 
+0

नहीं, यह प्रतीत नहीं होता अधिक व्याख्या करने के लिए: मैंने 'is' परिभाषा को बदल दिया है:' def है (x: Any) = scala.util.Try {as (x) .toString} .isSuccess', और यह अभी भी 'सत्य' देता है (यानी, कास्ट फेंक नहीं है)। यहां तक ​​कि यह 'def है (x: Any) = scala.util.Try {println (as (x) .toString)} .isSuccess;' खुशी से प्रिंट करता है "3" और सत्य देता है: -/ – Dima

+0

कृपया मेरा संपादन देखें –

+0

आह, अब समझ में आता है, धन्यवाद! 'है 'नहीं जानता कि' टी' क्या है, इसलिए यह तर्क को' किसी भी 'के रूप में मानता है। मैंने यह कोशिश की: 'विशेषता फू {def foo = ??? } कक्षा इंस्टेंट [टी <: फू] {डीफ़ है (एक्स: कोई भी) = scala.util.Try {as (x) .foo} .isSuccess; के रूप में def (x: कोई भी): टी = x.asInstanceOf [टी]; } '। अब 'नया इंस्टेंट [फू] .is (3)' अपेक्षित के रूप में 'झूठा 'लौटाता है। – Dima

2

जबकि @ 0 __ के जवाब बताता है कि क्यों यह काम नहीं करता है, तो यहां यह काम करने के लिए है:

class Inst[T](implicit tag: scala.reflect.ClassTag[T]) { 
    def is(x: Any) = tag.runtimeClass.isInstance(x) 
    // scala.util.Try { as(x) }.isSuccess will work as well 
    def as(x: Any): T = tag.runtimeClass.cast(x).asInstanceOf[T] 
} 

object Main extends App { 
    println(new Inst[String].is(3)) 
    println(new Inst[String].as(3)) 
} 


false 
java.lang.ClassCastException: Cannot cast java.lang.Integer to java.lang.String 
    at java.lang.Class.cast(Class.java:3369) 
... 
संबंधित मुद्दे