'टाइप' के लिए स्मार्ट कास्ट असंभव है, क्योंकि 'वेरिएबल' एक उत्परिवर्तनीय संपत्ति है जिसे इस समय तक बदला जा सकता था


275

और कोटलिन नौसिखिया पूछता है, "निम्न कोड संकलन क्यों नहीं होगा?":

    var left: Node? = null

    fun show() {
         if (left != null) {
             queue.add(left) // ERROR HERE
         }
    }

'नोड' के लिए स्मार्ट कास्ट असंभव है, क्योंकि 'लेफ्ट' एक उत्परिवर्तित संपत्ति है जिसे इस समय तक बदला जा सकता था

मुझे leftवह परिवर्तनशील चर मिल रहा है , लेकिन मैं स्पष्ट रूप से जाँच कर रहा हूं left != nullऔर leftटाइप का हूं Nodeइसलिए इसे उस प्रकार से स्मार्ट-कास्ट नहीं किया जा सकता है?

मैं इसे कैसे शान से ठीक कर सकता हूं? :)


3
कहीं एक अलग धागे के बीच का मान फिर से शून्य हो सकता है। मुझे यकीन है कि अन्य सवालों के जवाब में भी इसका उल्लेख है।
नहरमन

3
आप जोड़ने के लिए एक सुरक्षित कॉल का उपयोग कर सकते हैं
Whymarrh

धन्यवाद @nhaarman जो समझ में आता है, Whymarrh वह कैसे कर सकता है? मैंने सोचा था कि सुरक्षित कॉल केवल वस्तुओं के लिए नहीं थे
FRR

6
कुछ इस तरह: n.left?.let { queue.add(it) }मुझे लगता है?
जर्नी वर्नी

जवाबों:


357

के निष्पादन के बीच left != nullऔर queue.add(left)एक अन्य सूत्र के मूल्य बदल गया होगा leftकरने के लिए null

इसके आसपास काम करने के लिए आपके पास कई विकल्प हैं। यहाँ कुछ हैं:

  1. स्मार्ट कास्ट के साथ एक स्थानीय चर का उपयोग करें:

    val node = left
    if (node != null) {
        queue.add(node)
    }
  2. निम्न में से किसी एक जैसे सुरक्षित कॉल का उपयोग करें :

    left?.let { node -> queue.add(node) }
    left?.let { queue.add(it) }
    left?.let(queue::add)
  3. का प्रयोग करें एल्विस ऑपरेटर के साथ returnसंलग्न करते हुए समारोह से जल्दी वापस जाने के लिए:

    queue.add(left ?: return)

    ध्यान दें कि breakऔर continueलूप के भीतर जांच के लिए इसी तरह इस्तेमाल किया जा सकता है।


8
4. अपनी समस्या के लिए एक अधिक कार्यात्मक समाधान के बारे में सोचें जो कि परिवर्तनशील चर की आवश्यकता नहीं है।
गुड नाइट नर्ड प्राइड

1
@sak यह Nodeप्रश्न के मूल संस्करण में परिभाषित एक वर्ग का एक उदाहरण था जिसमें n.leftबस के बजाय अधिक जटिल कोड स्निपेट था left। मैंने उसी हिसाब से जवाब अपडेट किया है। धन्यवाद।
mfulton26

1
@sak वही अवधारणाएं लागू होती हैं। आप valप्रत्येक के लिए एक नया बना सकते हैं var, कई ?.letबयानों को घोंसला बना सकते हैं , या ?: returnअपने फ़ंक्शन के आधार पर कई बयानों का उपयोग कर सकते हैं। उदा MyAsyncTask().execute(a1 ?: return, a2 ?: return, a3 ?: return)। आप "मल्टीपल वैरिएबल लेट" के लिए किसी एक समाधान को भी आज़मा सकते हैं ।
mfulton26

1
@FARID किसका जिक्र कर रहे हैं?
mfulton26

3
हां, यह सुरक्षित है। जब एक चर को वर्ग वैश्विक घोषित किया जाता है, तो कोई भी धागा इसके मूल्य को संशोधित कर सकता है। लेकिन एक स्थानीय चर (एक फ़ंक्शन के अंदर घोषित एक चर) के मामले में, वह चर अन्य थ्रेड्स से उपलब्ध नहीं है, इसलिए उपयोग करने के लिए सुरक्षित है।
फरीद

31

1) इसके अलावा, आप उपयोग कर सकते हैं lateinitयदि आप यकीन है कि बाद में अपने प्रारंभ करना onCreate()या कहीं और।

इसे इस्तेमाल करो

lateinit var left: Node

इसके अलावा

var left: Node? = null

2) और एक अन्य तरीका है जो !!चर का उपयोग करते हैं जब आप इसे इस तरह से उपयोग करते हैं

queue.add(left!!) // add !!

यह क्या करता है?
c-

@ c-a यह आपके वैरिएबल को null के रूप में इनिशियलाइज़ करता है लेकिन बाद में कोड में इनिशियलाइज़ करना सुनिश्चित करता है।
राधेश

फिर, क्या यह वही नहीं है? @ राकेश
c-a

@ c-a किस के साथ?
राधेश

1
मैंने उपर्युक्त प्रश्न का उत्तर दिया कि 'नॉड' को स्मार्ट कास्ट करना असंभव है, क्योंकि 'लेफ्ट' एक उत्परिवर्तित गुण है जिसे इस समय तक बदला जा सकता था, यह कोड वैरिएबल प्रकार द्वारा उस त्रुटि को रोकता है। इसलिए कंपाइलर को स्मार्ट कास्ट की जरूरत नहीं है
राकेश

27

वहाँ mfulton26 के जवाब में लोगों के अलावा एक चौथा विकल्प है।

का उपयोग करके ?.ऑपरेटर से निपटने के बिना तरीकों के साथ-साथ खेतों कॉल करने के लिए संभव है letया स्थानीय चर का उपयोग कर।

संदर्भ के लिए कुछ कोड:

var factory: ServerSocketFactory = SSLServerSocketFactory.getDefault();
socket = factory.createServerSocket(port)
socket.close()//smartcast impossible
socket?.close()//Smartcast possible. And works when called

यह तरीकों, क्षेत्रों और अन्य सभी चीजों के साथ काम करता है जो मैंने इसे काम करने के लिए प्राप्त करने की कोशिश की।

इसलिए समस्या को हल करने के लिए, मैनुअल कास्ट का उपयोग करने या स्थानीय चर का उपयोग करने के बजाय, आप ?.विधियों को कॉल करने के लिए उपयोग कर सकते हैं ।

संदर्भ के लिए, इस Kotlin में परीक्षण किया गया था 1.1.4-3, लेकिन यह भी में परीक्षण किया 1.1.51और 1.1.60। इसकी कोई गारंटी नहीं है कि यह अन्य संस्करणों पर काम करता है, यह एक नई सुविधा हो सकती है।

?.ऑपरेटर का उपयोग करना आपके मामले में उपयोग नहीं किया जा सकता है क्योंकि यह एक पारित चर है जो समस्या है। एल्विस ऑपरेटर को एक विकल्प के रूप में इस्तेमाल किया जा सकता है, और यह शायद वह है जिसे कम से कम कोड की आवश्यकता होती है। continueहालांकि उपयोग करने के बजाय , returnभी इस्तेमाल किया जा सकता है।

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

queue.add(left as Node);

मतलब अगर बाएं एक अलग धागे पर बदल गया है, तो प्रोग्राम क्रैश हो जाएगा।


जहाँ तक मैं समझता हूँ, '?' ऑपरेटर जाँच कर रहा है कि क्या इसके बाईं ओर चर शून्य है .. ऊपर के उदाहरण में यह 'कतार' होगा। त्रुटि 'स्मार्ट कास्ट असंभव' पैरामीटर "लेफ्ट" को "ऐड" में पारित किए जाने की बात कर रहा है ... मुझे अभी भी त्रुटि मिलती है अगर मैं इस दृष्टिकोण का उपयोग करता हूं
FRR

सही है, त्रुटि है leftऔर नहीं queue। इसे जांचने की आवश्यकता है, एक मिनट में जवाब को संपादित करेगा
ज़ो

4

व्यावहारिक कारण यह काम नहीं करता धागे से संबंधित नहीं है। मुद्दा यह है कि node.leftप्रभावी ढंग से अनुवाद किया जाता है node.getLeft()

इस संपत्ति पाने वाले को इस रूप में परिभाषित किया जा सकता है:

val left get() = if (Math.random() < 0.5) null else leftPtr

इसलिए दो कॉल समान परिणाम नहीं दे सकते हैं।



1

यह करो:

var left: Node? = null

fun show() {
     val left = left
     if (left != null) {
         queue.add(left) // safe cast succeeds
     }
}

जो कि स्वीकृत उत्तर द्वारा प्रदान किया गया पहला विकल्प प्रतीत होता है, लेकिन वह वही है जो आप खोज रहे हैं।


यह "वाम" चर का छायांकन है?
AFD

जो पूरी तरह से ठीक है। Reddit.com/r/androiddev/comments/fdp2zq/…
EpicPandaForce

1

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


Android पर जैसे

रहें:

class MyVM : ViewModel() {
    fun onClick() {}
}

उपाय:

From: private lateinit var viewModel: ViewModel
To: private lateinit var viewModel: MyVM

उपयोग:

viewModel = ViewModelProvider(this)[MyVM::class.java]
viewModel.onClick {}

जीएल


1

आपका सबसे सुंदर समाधान होना चाहिए:

var left: Node? = null

fun show() {
    left?.also {
        queue.add( it )
    }
}

फिर आपको एक नए और अनावश्यक स्थानीय चर को परिभाषित करने की आवश्यकता नहीं है, और आपके पास कोई नया अभिकथन या कास्ट (जो DRY नहीं है) नहीं है। अन्य स्कोप फ़ंक्शंस भी काम कर सकते हैं इसलिए अपने पसंदीदा का चयन करें।


0

नहीं-नल मुखर ऑपरेटर का उपयोग करने का प्रयास करें ...

queue.add(left!!) 

3
खतरनाक। उसी कारण से ऑटो-कास्टिंग काम नहीं करता है।
याकूब ज़िमरमैन

3
यदि बायाँ अशक्त है तो यह ऐप क्रैश का कारण बन सकता है।
प्रीतम कर्मकार

0

मैं इसे कैसे लिखूंगा:

var left: Node? = null

fun show() {
     val left = left ?: return
     queue.add(left) // no error because we return if it is null
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.