2013-02-11 38 views
9

जावा जेनरिक अभिव्यक्ति के प्रकार के आधार पर जेनेरिक प्रकार पैरामीटर के प्रकार का अनुमान लगा सकता है। पर विचार करें निम्नलिखित:स्कैला और जावा जेनिक्स - नेस्टेड प्रकारों को निकालने और वापस करने के लिए

public static <T> T uncheckedCast(Object o) { 
    return (T)o; 
} 

हम इसे इस तरह के रूप कॉल कर सकते हैं:

Map<Baz,Bog> bazbogMap = new HashMap<Baz,Bog>(); 
String foo = uncheckedCast(bazbogMap); 

यह संकलन लेकिन एक RuntimeException फेंक जब यह शुरू हो जाती है, क्योंकि यह एक String को Map कास्ट करने के लिए कोशिश करेंगे लेकिन असफल । लेकिन मुद्दा यह है कि जावा ने <T> के मूल्य को कॉलसाइट पर अपेक्षित परिणामी प्रकार के आधार पर अनुमानित किया।

हम भी साथ स्काला में ऐसा कर सकते हैं: अब तक

def uncheckedCast[T](o: AnyRef): T = o.asInstanceOf[T] 

, तो अच्छा।

जावा भी नेस्टेड परिभाषाओं से प्रकार तर्क प्राप्त करेगा और उन (यानी हम वास्तव में उपयोग करने से पहले के रूप में ऊपर के लिए इसका इस्तेमाल करने के लिए एक प्रकार के परिणाम आवंटित करने के लिए नहीं है।; जावा जानता है क्या यह पहले से ही है) लौट सकते हैं

एक साधारण इस दिखा वर्ग:

import java.util.HashMap; 
import java.util.Map; 

public class KeysAndValues { 
    public interface Key<T> {} 
    public static class StringKey implements Key<String> {} 

    private final Map<Class<?>, Object> lookup; 

    public KeysAndValues() { 
     lookup = new HashMap<Class<?>, Object>(); 
    } 

    @SuppressWarnings("unchecked") 
    public <V, K extends Key<V>> V put(Class<K> key, V value) { 
     return (V) lookup.put(key, value); 
    } 

    @SuppressWarnings("unchecked") 
    public <V, K extends Key<V>> V get(Class<K> key) { 
     return (V) lookup.get(key); 
    } 

    public static void test() { 
     KeysAndValues kv = new KeysAndValues(); 
     kv.put(StringKey.class, "BAM!"); // returns null 
     kv.put(StringKey.class, "BOOM!"); // returns "BAM!" 
     kv.get(StringKey.class); // returns "BOOM!" 
    } 
} 

हालांकि, स्काला में इस वर्ग समस्याओं का कारण बनता। आरईपीएल: के रूप में V पैरामीटर की जरूरत है

scala> val kv = new KeysAndValues 
kv: KeysAndValues = [email protected] 

scala> import KeysAndValues.StringKey 
import KeysAndValues.StringKey 

scala> kv.put(classOf[StringKey], "BAM!") 
res0: java.lang.String = null 

scala> kv.put(classOf[StringKey], "BOOM!") 
res1: java.lang.String = BAM! 

scala> kv.get(classOf[StringKey]) 
<console>:10: error: inferred type arguments [Nothing,KeysAndValues.StringKey] do not conform to method get's type parameter bounds [V,K <: KeysAndValues.Key[V]] 
       kv.get(classOf[StringKey]) 

put() करने के लिए दो कॉल V प्रकार पैरामीटर है जो उन्हें काम करने के लिए अनुमति देता है के लिए एक मूल्य निर्दिष्ट करते हैं, लेकिन जैसे ही K पैरामीटर की विरासत से निकाला जाता था, चीजों को तोड़ने नीचे। जावा कोड में ऐसा कोई मुद्दा नहीं है।

एक ही रास्ता स्काला प्राप्त करने के लिए शिकायत करने के लिए नहीं स्पष्ट रूप से परिभाषित करने के लिए प्रकार है:

kv.get[String, StringKey](classOf[StringKey]) 

(कुछ सरल के लिए और की तरह काल्पनिक ऊपर यह मामूली बात नहीं (सूखी उल्लंघन करता है), लेकिन और अधिक शामिल कुछ के लिए, स्टैनफोर्ड कोर NLP एपीआई, आप की तरह कुछ करने के लिए जहां की तरह:

doc.get[java.util.Map[Integer, CorefChain], CorefChainAnnotation](classOf[CorefChainAnnotation]) 

कौन सा मैन्युअल ताकि आप उन्हें जोड़ सकते हैं नेस्टेड प्रकार को देख भी शामिल है, काफी दर्द है)

प्रश्न (ओं):

क्या टाइप पैरामीटर को बिना किसी शब्द के निर्दिष्ट किए बिना काम करने के लिए कोई तरीका है? सबसे महत्वपूर्ण बात यह है कि यह किस समस्या से शुरू हो रहा है? जावा स्केल नहीं होने पर टाइप तर्क का अनुमान लगाने में सक्षम कैसे है?

संपादित करें 1: कोड स्टैनफोर्ड कोर NLP समस्या का प्रदर्शन का सबसे निकाला गया और स्काला/जावा जेनरिक कि इस मुद्दे को एक मिसाल है में अंतर का एक सामान्य उदाहरण के साथ यह बदल दिया।

+0

क्या आप बाहरी पुस्तकालयों के बिना संकलित सादे जावा और स्कैला कोड में अपनी समस्या का पुनरुत्पादन कर सकते हैं? –

+0

शायद। मुझे उस पर एक दरार लेने दो। –

+0

अंतर दिखाने वाला जावा क्लास और आरईपीएल आउटपुट जोड़ा गया। –

उत्तर

3

वास्तव में क्यों स्काला जावा प्रकार पैरामीटर अनुमान नहीं लगा सकता मैं आपको नहीं बता सकता है, लेकिन मैं कम से कम दिखाते हैं कि जावा में प्रकार पैरामीटर घोषित करने के लिए कर सकते हैं ताकि स्काला उन्हें अनुमान लगा सकते हैं:

@SuppressWarnings("unchecked") 
public <V> V put(Class<? extends Key<V>> key, V value) { 
    return (V) lookup.put(key, value); 
} 

@SuppressWarnings("unchecked") 
public <V> V get(Class<? extends Key<V>> key) { 
    return (V) lookup.get(key); 
} 

मुझे लगता है कि यहां प्रमुख मुद्दा है कि आप क्या करते हैं नहीं बिल्कुल जरूरत कि K प्रकार पैरामीटर - एक वाइल्डकार्ड प्रकार पैरामीटर, ? extends Key<V> आप ही कार्यक्षमता दे देंगे। यह तो किसी भी प्रकार पैरामीटर निर्दिष्ट किए बिना ही स्काला से खुशी से काम करता है:

scala> kv.put(classOf[StringKey], "BAM!") 
res0: String = null 

scala> kv.get(classOf[StringKey]) 
res1: String = BAM! 

संपादित करें:

यहाँ सबसे अच्छा मैं एक वैकल्पिक हल के लिए कर पाते थे। इसके लिए उच्च प्रकार के प्रकार और एक कलाकार की आवश्यकता होती है। यकीन नहीं है कि मैं समझा सकता हूं कि यह क्यों संकलित करता है लेकिन दूसरा संस्करण हालांकि नहीं है। ;-)

scala> import KeysAndValues._ 
import KeysAndValues._ 

scala> import scala.language.higherKinds 
import scala.language.higherKinds 

scala> def get[V, K[X] <: Key[X]](kv: KeysAndValues, key: Class[_ <: K[V]]) = 
    | kv.get[V, K[V]](key.asInstanceOf[Class[K[V]]]) 
get: [V, K[X] <: KeysAndValues.Key[X]](kv: KeysAndValues, key: Class[_ <: K[V]])V 

scala> val kv = new KeysAndValues 
kv: KeysAndValues = [email protected] 

scala> kv.put(classOf[StringKey], "BAM!") 
res0: String = null 

scala> get(kv, classOf[StringKey]) 
res1: String = BAM! 
+0

यह एक अच्छा आंशिक उत्तर है। मेरा उदाहरण स्टैनफोर्ड कोर एनएलपी से लिया गया था, जहां मैं स्रोत संपादित नहीं कर सकता। मैं अभी भी जानना चाहूंगा कि क्या एक और स्कैला केवल कामकाज (असंभव है?) और स्कैला/जावा के बीच यह अंतर क्यों मौजूद है। –

+0

मैंने इस मुद्दे के बारे में स्टैनफोर्ड कोर एनएलपी लोगों से संपर्क किया, और मेरा मानना ​​है कि स्टैनफोर्ड कोर एनएलपी 1.3.5 के रूप में, अब वे मेरे उत्तर की शुरुआत में प्रस्तावित सरल जेनेरिक का उपयोग करते हैं। तो आप स्टैनफोर्ड कोर एनएलपी 1.3.5 में अपग्रेड करने का प्रयास कर सकते हैं और देख सकते हैं कि इससे समस्या हल हो जाती है या नहीं। – Steve

+0

उपयोगिता दृष्टिकोण से यह अच्छी खबर है; मैं अभी भी जानना चाहता हूं कि क्यों जावा और स्कैला में यह अंतर है। –