'টাইপ' এ স্মার্ট কাস্ট করা অসম্ভব, কারণ 'ভেরিয়েবল' একটি পরিবর্তনীয় সম্পত্তি যা এই সময়ের মধ্যে পরিবর্তন করা যেতে পারে


275

এবং কোটলিন নবাগত জিজ্ঞাসা করেছেন, "নিম্নলিখিত কোডগুলি সংকলন করবে না কেন?":

    var left: Node? = null

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

'নোড' এ স্মার্ট কাস্ট করা অসম্ভব, কারণ 'বাম' একটি পরিবর্তনীয় সম্পত্তি যা এই সময়ের মধ্যে পরিবর্তন করা যেতে পারে

আমি leftতা পরিবর্তনীয় পরিবর্তনশীল, তবে আমি স্পষ্টভাবে যাচাই করছি left != nullএবং leftটাইপের Nodeতাই এটি কেন সেই ধরণের স্মার্ট কাস্টেড হতে পারে না?

আমি কীভাবে এটি মার্জিতভাবে ঠিক করতে পারি? :)


3
কোথাও কোথাও কোনও আলাদা থ্রেডের মানটি আবার নালায় পরিবর্তন করতে পারে। আমি নিশ্চিত অন্যান্য প্রশ্নের উত্তরগুলিও সে সম্পর্কে উল্লেখ করে।
nhaarman

3
আপনি একটি ব্যবহার করতে পারে নিরাপদ কল যোগ করার জন্য
Whymarrh

ধন্যবাদ @ নহার্মান, যে বোধগম্য হয়, কেন মমরহ তা করতে পারে? আমি ভেবেছিলাম নিরাপদ কলগুলি কেবল কোনও
জিনিসের

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
৪. আপনার সমস্যার আরও কার্যকর ক্রিয়াকলাপের সমাধানের বিষয়ে ভাবুন যার জন্য পরিবর্তনীয় ভেরিয়েবলের প্রয়োজন হয় না।
শুভরাত্রি

1
@ সাক এটি Nodeপ্রশ্নের মূল সংস্করণে সংজ্ঞায়িত এমন একটি শ্রেণীর উদাহরণ যা সাধারণ n.leftপরিবর্তে আরও জটিল কোড স্নিপেট ছিল left। আমি সেই অনুযায়ী উত্তর আপডেট করেছি। ধন্যবাদ।
mfulton26

1
@ সাক একই ধারণাটি প্রযোজ্য। আপনি valপ্রতিটি জন্য একটি নতুন তৈরি করতে পারেন var, নীড় বেশ কয়েকটি ?.letবিবৃতি, বা ?: returnআপনার ফাংশন উপর নির্ভর করে বেশ কয়েকটি বিবৃতি ব্যবহার করতে পারেন । যেমন MyAsyncTask().execute(a1 ?: return, a2 ?: return, a3 ?: return)। আপনি "একাধিক ভেরিয়েবল চলুন" এর সমাধানগুলির একটিরও চেষ্টা করতে পারেন ।
mfulton26

1
@ ফরিদ কে উল্লেখ করছেন?
mfulton26

3
হ্যাঁ, এটি নিরাপদ। যখন কোনও ভেরিয়েবলকে ক্লাস গ্লোবাল হিসাবে ঘোষণা করা হয়, যে কোনও থ্রেড তার মানটি পরিবর্তন করতে পারে। তবে স্থানীয় ভেরিয়েবলের ক্ষেত্রে (কোনও ফাংশনের অভ্যন্তরে একটি ভেরিয়েবল ঘোষিত) ক্ষেত্রে, সেই পরিবর্তনশীলটি অন্য থ্রেড থেকে পৌঁছানো যায় না, তাই ব্যবহারে নিরাপদ।
ফরিদ

31

1) এছাড়াও আপনি ব্যবহার করতে পারেন lateinitযদি আপনি নিশ্চিত পরে আপনার আরম্ভের নাonCreate() বা অন্যত্র।

এটা ব্যবহার কর

lateinit var left: Node

এর পরিবর্তে

var left: Node? = null

2) এবং অন্যান্য উপায় আছে যে !!যখন ভেরিয়েবলের শেষ ব্যবহার হয় যখন আপনি এটি ব্যবহার করেন

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

এটার কাজ কি?
সি-

@ সি-এ এটি আপনার পরিবর্তনশীলটিকে শূন্য হিসাবে আরম্ভ করে তোলে তবে কোডের পরে এটি আরম্ভ করার বিষয়টি নিশ্চিত করে।
রাদেশ

তাহলে, এটা কি এক নয়? @ রাদেশ
সি-এ

@ সি-কি একই সাথে?
রাদেশ

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);

অর্থ যদি বামে অন্য কোনও থ্রেডে পরিবর্তিত হয়ে থাকে তবে প্রোগ্রামটি ক্রাশ হয়ে যাবে।


আমি যতদূর বুঝতে পেরেছি, ''? ' অপারেটর চেক করছে যে তার বাম দিকের ভেরিয়েবলটি নাল কিনা .. উপরের উদাহরণে এটি 'সারি' হবে। ত্রুটি 'স্মার্ট কাস্ট অসম্ভব' প্যারামিটারটি "বাম" পদ্ধতিতে "অ্যাড" পাস করার বিষয়ে উল্লেখ করছে ... আমি যদি এই পদ্ধতির ব্যবহার করি তবে আমি ত্রুটিটি পেয়েছি
এফআরআর

ঠিক আছে, ত্রুটিটি চালু আছে 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
     }
}

কোনটি গ্রহণযোগ্য উত্তর দ্বারা সরবরাহিত প্রথম বিকল্প বলে মনে হয়, তবে আপনি এটি সন্ধান করছেন।


এই "বাম" পরিবর্তনশীল ছায়া?
এএফডি


1

বৈশিষ্ট্যগুলির একটি স্মার্ট কাস্ট হওয়ার জন্য, সম্পত্তির ডেটা ধরণটি এমন শ্রেণি হতে হবে যাতে আপনি যে পদ্ধতি বা আচরণটি অ্যাক্সেস করতে চান তা থাকতে হবে এবং সম্পত্তিটি সুপার শ্রেণীর ধরণের নয়।


যেমন অ্যান্ড্রয়েডে

থাকা:

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 )
    }
}

তারপরে আপনাকে নতুন এবং অপ্রয়োজনীয় স্থানীয় ভেরিয়েবলের সংজ্ঞা দিতে হবে না এবং আপনার কোনও নতুন জোর বা ক্যাসেট নেই (যা ডিআরওয়াই নয়)। অন্যান্য স্কোপ ফাংশনগুলিও কাজ করতে পারে তাই আপনার পছন্দসইটি বেছে নিন।


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
}
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.