স্কালায় ভাল-পরিবর্তনীয় বনাম ভার-অপরিবর্তনীয়


100

অপরিবর্তনীয় সংগ্রহ সহ ভার ব্যবহার করে কোনও পরিবর্তনীয় সংগ্রহের সাথে ভাল ব্যবহার করার ক্ষেত্রে স্কালায় কোনও নির্দেশিকা রয়েছে? বা অবিরত সংগ্রহের সাথে আপনার সত্যিই লক্ষ্য করা উচিত?

উভয় ধরণের সংগ্রহ রয়েছে এই বিষয়টি আমাকে প্রচুর পছন্দ দেয় এবং প্রায়শই আমি কীভাবে পছন্দ করতে পারি তা আমি জানি না।


উদাহরণস্বরূপ দেখুন stackoverflow.com/questions/10999024/...
লুইজি Plinge

উত্তর:


105

খুব সাধারণ প্রশ্ন, এই এক। কঠিন জিনিসটি সদৃশগুলি সন্ধান করছে।

রেফারেন্সিয়াল স্বচ্ছতার জন্য আপনার প্রচেষ্টা করা উচিত । এর অর্থ কী, যদি আমার "ই" এর একটি ভাব থাকে তবে আমি এটি তৈরি করতে val x = eএবং এর সাথে প্রতিস্থাপন eকরতে পারি x। এটি এমন সম্পত্তি যা মিউটিলিটি ভেঙে যায়। যখনই আপনাকে কোনও ডিজাইনের সিদ্ধান্ত নেওয়ার দরকার হবে, রেফারেন্সিয়াল স্বচ্ছতার জন্য সর্বাধিক করুন।

ব্যবহারিক বিষয় হিসাবে, একটি পদ্ধতি-স্থানীয় varহ'ল যে নিরাপদ varবিদ্যমান, যেহেতু এটি পদ্ধতিটি এড়ায় না। পদ্ধতিটি যদি ছোট হয় তবে আরও ভাল। যদি তা না হয় তবে অন্যান্য পদ্ধতিগুলি বের করে এটিকে হ্রাস করার চেষ্টা করুন।

অন্যদিকে, একটি পরিবর্তনীয় সংগ্রহের সম্ভাবনা রয়েছে পালানোর । কোড পরিবর্তন করার সময়, আপনি এটি অন্য পদ্ধতিতে পাস করতে বা এটি ফিরিয়ে দিতে চাইতে পারেন। এটাই সেই ধরণের জিনিস যা রেফারেনশিয়াল স্বচ্ছতা ভঙ্গ করে।

একটি বস্তুতে (একটি ক্ষেত্র), প্রায় একই জিনিস ঘটে তবে আরও মারাত্মক পরিণতি সহ। যে কোনও উপায়ে বস্তুর স্থিতি থাকবে এবং অতএব, রেফারেন্সিয়াল স্বচ্ছতা ভঙ্গ করুন। তবে একটি পরিবর্তনীয় সংগ্রহের অর্থ এমনকি কোনও ব্যক্তি এটি পরিবর্তন করছে তার নিয়ন্ত্রণও হারাতে পারে।


39
নাইস, আমার মনের মধ্যে নতুন বড় ছবি: পছন্দ immutable valউপর immutable varউপর mutable valউপর mutable var। বিশেষ করে immutable varশেষ mutable val!
পিটার স্মিটজ

4
মনে রাখবেন যে আপনি এখনও স্থানীয় পার্শ্ব পরিবর্তনীয় (বন্ধ করে দিতে পারে এমন একটি পার্শ্ব-কার্যকর "ফাংশন" যা এটি পরিবর্তন করতে পারে) বন্ধ করে দিতে পারে var। অপরিবর্তনীয় সংগ্রহগুলি ব্যবহারের আর একটি দুর্দান্ত বৈশিষ্ট্য হ'ল আপনি পুরানো কপিগুলি দক্ষতার সাথে চারপাশে রাখতে পারবেন, এমনকি যদি varপরিবর্তন হয়।
রহস্যময় ড্যান

4
TL; ড: পছন্দ করা var x: Set[Int] ওভার val x: mutable.Set[Int] থেকে যদি আপনি পাস xসাবেক ক্ষেত্রে, কিছু অন্যান্য ফাংশন, আপনি কি নিশ্চিত পরিবর্তন ঘটান করতে পারেন না যে ফাংশন, xআপনার জন্য।
পথিক্রিত

17

যদি আপনি অবিচ্ছেদ্য সংগ্রহগুলি নিয়ে কাজ করেন এবং আপনার সেগুলি "সংশোধন" করা দরকার, উদাহরণস্বরূপ, এগুলিতে একটি লুপে যুক্ত করুন, তবে আপনাকে varফলাফলগুলি ব্যবহার করতে হবে কারণ ফলস্বরূপ সংগ্রহটি আপনার কোথাও সংরক্ষণ করতে হবে। আপনি যদি কেবল অপরিবর্তনীয় সংগ্রহগুলি থেকে পড়ে থাকেন তবে valএস ব্যবহার করুন ।

সাধারণভাবে, নিশ্চিত হয়ে নিন যে আপনি উল্লেখ এবং অবজেক্টগুলিকে বিভ্রান্ত করবেন না don't valগুলি হ'ল অপরিবর্তনীয় রেফারেন্স (সি-এ ধ্রুবক পয়েন্টার)। এটি হ'ল, যখন আপনি ব্যবহার করবেন val x = new MutableFoo(), আপনি যে পয়েন্টটি দেখিয়েছেন তা পরিবর্তন করতে সক্ষম xহবেন, তবে আপনি কোন বস্তুর x পয়েন্টগুলিতে পরিবর্তন করতে পারবেন না । বিপরীত ধারনা যদি আপনি ব্যবহার var x = new ImmutableFoo()। আমার প্রাথমিক পরামর্শটি গ্রহণ করা: যদি আপনাকে কোন বিষয়টিকে কোনও রেফারেন্স পয়েন্ট পরিবর্তন করতে হয় না, তবে valএস ব্যবহার করুন ।


4
var immutable = something(); immutable = immutable.update(x)অপরিবর্তনীয় সংগ্রহ ব্যবহারের উদ্দেশ্যকে পরাস্ত করে। আপনি ইতিমধ্যে রেফারেন্সিয়াল স্বচ্ছতা ছেড়ে দিয়েছেন এবং ভাল সময়ের জটিলতার সাথে আপনি সাধারণত একটি পরিবর্তনীয় সংগ্রহ থেকে একই প্রভাব পেতে পারেন। চারটি সম্ভাবনার ( valএবং var, পরিবর্তনীয় এবং অপরিবর্তনীয়) এর মধ্যে এটি একটি স্বল্পতম ধারণা দেয়। আমি প্রায়শই ব্যবহার করি val mutable
জিম পিভারস্কি

4
@ জিমপিভারস্কি আমি অন্যদের মতো ড্যানিয়েলের উত্তর এবং পিটারের মন্তব্য দেখুন। আপনার যদি কোনও ডেটা স্ট্রাকচার আপডেট করতে হয়, তবে মিউটেবল ভেলের পরিবর্তে অপরিবর্তনীয় ভার ব্যবহারের ফলে আপনি ডাব্লু / ও কাঠামোর কাঠামোর রেফারেন্সগুলি ফাঁস করে নিতে পারেন যে এটি অন্যের দ্বারা আপনার স্থানীয় অনুমানকে ভেঙে এমনভাবে সংশোধন করে। এই "অন্য" এর অসুবিধা হ'ল তারা বাসি ডেটা পড়তে পারে।
মাল্টে শোয়ারহফ

আমি আমার মন পরিবর্তন করেছি এবং আমি আপনার সাথে একমত (আমি ইতিহাসের জন্য আমার মূল মন্তব্যটি রেখে যাচ্ছি)। আমি তখন থেকে এটি ব্যবহার করেছি, বিশেষত var list: List[X] = Nil; list = item :: list; ...এবং আমি ভুলে গিয়েছি যে আমি একবার অন্যভাবে লিখেছিলাম।
জিম পিভারস্কি

@ মাল্টশ্যাওয়ারফোফ: ধারাবাহিকতা যদি গুরুত্বপূর্ণ হয় তবে আপনার প্রোগ্রামটি কীভাবে ডিজাইন করেছেন তার উপর নির্ভর করে "বাসি ডেটা" আসলেই কাম্য; এটি ক্লোজুরে কীভাবে একযোগে কাজ করে তার মূল অন্তর্নিহিত নীতিগুলির মধ্যে একটি।
এরিক কাপলুন

@ এরিক অলিক আমি বলব না যে বাসি ডেটা প্রতি সেঞ্চে আকাঙ্ক্ষিত, তবে আমি সম্মত হই যে আপনি আপনার ক্লায়েন্টদের যে গ্যারান্টি / প্রয়োজনীয় গ্যারান্টি দিতে চান তার উপর নির্ভর করে এটি পুরোপুরি ঠিকঠাক হতে পারে। বা আপনার কী এমন উদাহরণ রয়েছে যেখানে বাসি ডেটা পড়ার একমাত্র সত্যটি আসলে একটি সুবিধা? আমি বাসি ডেটা গ্রহণের পরিণতি বলতে চাই না, এটি আরও ভাল পারফরম্যান্স বা একটি সহজ এপিআই হতে পারে।
মাল্টে শোওয়ারহফ

9

এর উত্তর দেওয়ার সর্বোত্তম উপায় হল একটি উদাহরণ। ধরুন আমাদের কোনও প্রক্রিয়া রয়েছে কিছু কারণে কেবল সংখ্যা সংগ্রহ করা। আমরা এই নম্বরগুলি লগ করতে ইচ্ছুক, এবং এটি করার জন্য সংগ্রহটি অন্য প্রক্রিয়াতে প্রেরণ করব ।

লোগারে সংগ্রহটি পাঠানোর পরে অবশ্যই আমরা সংখ্যা সংগ্রহ করছি। এবং আসুন আমরা লগিং প্রক্রিয়াতে কিছু ওভারহেড রয়েছে যা আসল লগিংয়ে বিলম্ব করে। আশা করি আপনি দেখতে পাচ্ছেন এটি কোথায় চলছে।

যদি আমরা এই সংগ্রহটি কোনও পরিবর্তনীয় val, (পরিবর্তনযোগ্য কারণ আমরা ক্রমাগত এটি যোগ করে চলেছি) সংরক্ষণ করি তবে এর অর্থ হ'ল লগিংয়ের প্রক্রিয়াটি একই অবজেক্টের দিকে তাকাবে যা এখনও আমাদের সংগ্রহ প্রক্রিয়া দ্বারা আপডেট হচ্ছে। এই সংগ্রহটি যে কোনও সময় আপডেট হতে পারে এবং তাই যখন লগ করার সময় হয় আমরা আসলে আমাদের পাঠানো সংগ্রহটি লগইন করতে পারি না।

যদি আমরা কোনও পরিবর্তনযোগ্য ব্যবহার না করে থাকি তবে আমরা varলগারকে একটি অপরিবর্তনীয় ডেটা কাঠামো প্রেরণ করি। আমরা আমাদের সংগ্রহে আরো সংখ্যার যোগ করেন, তখন আমরা হতে হবে প্রতিস্থাপন আমাদের varএকটি সঙ্গে নতুন অপরিবর্তনীয় ডাটা স্ট্রাকচার । এর অর্থ এই নয় যে লগারে পাঠানো সংগ্রহটি প্রতিস্থাপন করা হয়েছে! এটি এখনও সংগ্রহটি প্রেরণ করা হয়েছে যা এটি পাঠানো হয়েছিল। সুতরাং আমাদের লগার প্রকৃতপক্ষে এটি প্রাপ্ত সংগ্রহটি লগ করবে।


1

আমি মনে করি যে এই ব্লগ পোস্টের উদাহরণগুলি আরও আলোকপাত করবে, কারণ কোন কম্বো ব্যবহার করা উচিত তা প্রশ্নে সমঝোতার পরিস্থিতিগুলিতে আরও বেশি গুরুত্বপূর্ণ হয়ে ওঠে: সমঝোতার জন্য অপরিবর্তনীয়তার গুরুত্ব । এবং যখন আমরা এটি পেয়েছি তখন অ্যাটমিকরাইফেন্সের মতো কিছু বনাম @ ভোলটাইল বনাম সিঙ্ক্রোনাইজড এর পছন্দসই ব্যবহারটি নোট করুন: তিনটি সরঞ্জাম


-2

var immutable বনাম val mutable

এই প্রশ্নের অনেক দুর্দান্ত উত্তর ছাড়াও। এখানে একটি সাধারণ উদাহরণ, যা এর সম্ভাব্য বিপদগুলি তুলে ধরে val mutable:

পরিবর্তনীয় অবজেক্টগুলি পদ্ধতির অভ্যন্তরে পরিবর্তিত হতে পারে, যা সেগুলি প্যারামিটার হিসাবে গ্রহণ করে, যখন পুনরায় নিয়োগের অনুমতি নেই।

import scala.collection.mutable.ArrayBuffer

object MyObject {
    def main(args: Array[String]) {

        val a = ArrayBuffer(1,2,3,4)
        silly(a)
        println(a) // a has been modified here
    }

    def silly(a: ArrayBuffer[Int]): Unit = {
        a += 10
        println(s"length: ${a.length}")
    }
}

ফলাফল:

length: 5
ArrayBuffer(1, 2, 3, 4, 10)

এরকম কিছু ঘটতে পারে না var immutable, কারণ পুনরায় নিয়োগের অনুমতি নেই:

object MyObject {
    def main(args: Array[String]) {
        var v = Vector(1,2,3,4)
        silly(v)
        println(v)
    }

    def silly(v: Vector[Int]): Unit = {
        v = v :+ 10 // This line is not valid
        println(s"length of v: ${v.length}")
    }
}

ফলাফল স্বরূপ:

error: reassignment to val

যেহেতু ফাংশন প্যারামিটারগুলি valপুনরায় নিয়োগের অনুমতি দেওয়া হয় না বলে চিকিত্সা করা হয়।


এটি ভুল। আপনি যে ত্রুটিটি পেয়েছিলেন তার কারণ হ'ল আপনি ভেক্টরটিকে আপনার দ্বিতীয় উদাহরণে ব্যবহার করেছেন যা পূর্বনির্ধারিতভাবে অপরিবর্তনীয়। আপনি যদি একটি অ্যারেবফার ব্যবহার করেন তবে দেখতে পাবেন এটি সূক্ষ্ম সংকলন করে এবং একই জিনিসটি যেখানে এটি নতুন উপাদানটিতে যুক্ত করে এবং পরিবর্তিত বাফারটি মুদ্রণ করে। পেস্টবিন.
com

@ এডজক্যাসবার্গ, আমি আমার দ্বিতীয় উদাহরণে ইচ্ছাকৃতভাবে একটি ভেক্টর ব্যবহার করছি, কারণ আমি এটি দেখানোর চেষ্টা করছি যে প্রথম উদাহরণটির সাথে আচরণটি mutable valসম্ভব নয় immutable var। এখানে কি ভুল?
আকাওয়াল

আপনি আপেলকে কমলার সাথে তুলনা করছেন। ভেক্টরের +=অ্যারে বাফারের মতো কোনও পদ্ধতি নেই । আপনার উত্তর যে বোঝা +=একই হিসাবে x = x + yযার ফলে এটি নয়। আপনার বক্তব্য যে ফাংশন প্যারামগুলি ভ্যালস হিসাবে বিবেচনা করা হবে তা সঠিক এবং আপনি যে ত্রুটিটি উল্লেখ করেছেন তা পেয়েছেন তবে কেবল আপনি ব্যবহার করেছেন =। আপনি অ্যারেবফারের সাথে একই ত্রুটিটি পেতে পারেন তাই এখানে সংগ্রহগুলি মিউটিবিলিটি সত্যিই প্রাসঙ্গিক নয়। সুতরাং এটি একটি ভাল উত্তর নয় কারণ ওপি কী বলছে তা পেয়েছে না। যদিও আপনি যদি না চান তবে আশেপাশে একটি পরিবর্তনীয় সংগ্রহ পাস করার ঝুঁকির একটি ভাল উদাহরণ।
এজ কেসবার্গ

@EdgeCaseBerg কিন্তু আপনি আচরণ আমি পেতে প্রতিলিপি করতে পারবে না ArrayBuffer, ব্যবহার করে Vector। ওপির প্রশ্নটি বিস্তৃত, তবে তারা কখন কোনটি ব্যবহার করবেন সে সম্পর্কে পরামর্শের সন্ধান করছিলেন, তাই আমার বিশ্বাস আমার উত্তরটি দরকারী কারণ এটি পরিবর্তনীয় সংগ্রহের চারপাশে যাওয়ার বিপদগুলি চিত্রিত করে (সত্য যে এটি valসাহায্য করে না); immutable varতুলনায় নিরাপদ mutable val
আকাওয়াল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.