প্রথম, নোট করুন যে এই আচরণটি কেবলমাত্র অ্যারে নয়, পরিবর্তিত (যেমন হ্যাশ এবং স্ট্রিংগুলি) কোনও ডিফল্ট মানের ক্ষেত্রে প্রযোজ্য।
টিএল; ডিআর : Hash.new { |h, k| h[k] = [] }
আপনি সর্বাধিক প্রতিমা সমাধান চাইলে এবং কেন এটি যত্ন করবেন না তা ব্যবহার করুন।
কি কাজ করে না
কেন Hash.new([])
কাজ করে না
আসুন কেন Hash.new([])
কাজ করে না তা আরও গভীরতার সাথে দেখি :
h = Hash.new([])
h[0] << 'a' #=> ["a"]
h[1] << 'b' #=> ["a", "b"]
h[1] #=> ["a", "b"]
h[0].object_id == h[1].object_id #=> true
h #=> {}
আমরা দেখতে পাচ্ছি যে আমাদের ডিফল্ট অবজেক্টটি পুনঃব্যবহৃত এবং রূপান্তরিত হচ্ছে (এটি কারণ এটি একমাত্র এবং একমাত্র পূর্বনির্ধারিত মান হিসাবে উত্তীর্ণ হয়েছে, হ্যাশের একটি নতুন, নতুন ডিফল্ট মান পাওয়ার কোনও উপায় নেই), তবে কী বা কী মান নেই? অ্যারে, h[1]
তবুও আমাদের একটি মান দেওয়া সত্ত্বেও ? এখানে একটি ইঙ্গিত দেওয়া হয়েছে:
h[42] #=> ["a", "b"]
প্রতিটি []
কল দ্বারা ফিরে আসা অ্যারে হ'ল কেবলমাত্র ডিফল্ট মান, যা আমরা এই সময়টি পরিবর্তিত করে চলেছি তাই এখন আমাদের নতুন মান রয়েছে। যেহেতু <<
হ্যাশ নির্ধারিত না (সেখানে কখনোই ছাড়া রুবি মধ্যে নিয়োগ হতে পারে =
বর্তমান † ), আমরা কখনোই আমাদের প্রকৃত হ্যাশ মধ্যে কিছু রেখেছি। পরিবর্তে আমাদের ব্যবহার করতে হবে <<=
(যা <<
হিসাবে +=
রয়েছে +
):
h[2] <<= 'c' #=> ["a", "b", "c"]
h #=> {2=>["a", "b", "c"]}
এটি একই হিসাবে:
h[2] = (h[2] << 'c')
কেন Hash.new { [] }
কাজ করে না
ব্যবহার Hash.new { [] }
সমাধান পুনঃব্যবহার এবং মূল ডিফল্ট মান mutating (হিসেবে দেওয়া ব্লক প্রতিটি সময় বলা হয়, একটি নতুন অ্যারে ফিরে) সমস্যা, কিন্তু না নিয়োগ সমস্যা:
h = Hash.new { [] }
h[0] << 'a' #=> ["a"]
h[1] <<= 'b' #=> ["b"]
h #=> {1=>["b"]}
কি কাজ করে
অ্যাসাইনমেন্টের উপায়
আমরা যদি সর্বদা ব্যবহারের কথা মনে করি <<=
, তবে Hash.new { [] }
এটি একটি কার্যকর সমাধান, তবে এটি কিছুটা বিজোড় এবং অহঙ্কারী (আমি বুনোতে কখনও দেখিনি <<=
)। যদি <<
অজান্তে ব্যবহার করা হয় তবে এটি সূক্ষ্ম বাগের প্রবণও।
পরিবর্তনীয় উপায়
ডকুমেন্টেশনHash.new
রাজ্যের (জোর আমার নিজের):
যদি কোনও ব্লক নির্দিষ্ট করা থাকে, তবে এটি হ্যাশ অবজেক্ট এবং কী দ্বারা কল করা হবে এবং এটি ডিফল্ট মানটি ফিরিয়ে আনবে। যদি প্রয়োজন হয় তবে হ্যাশে মান সংরক্ষণ করা ব্লকের দায়িত্ব ।
সুতরাং আমরা অবশ্যই পরিবর্তে হ্যাশটিতে ডিফল্ট মানটি সংরক্ষণ করতে চাই যদি আমরা এর <<
পরিবর্তে ব্যবহার করতে চাই <<=
:
h = Hash.new { |h, k| h[k] = [] }
h[0] << 'a' #=> ["a"]
h[1] << 'b' #=> ["b"]
h #=> {0=>["a"], 1=>["b"]}
এটি কার্যকরভাবে আমাদের পৃথক কলগুলি (যা ব্যবহার করবে <<=
) থেকে পাস করা ব্লকে অ্যাসাইনমেন্টটি স্থানান্তরিত করে Hash.new
, ব্যবহার করার সময় অপ্রত্যাশিত আচরণের বোঝা সরিয়ে দেয় <<
।
মনে রাখবেন যে এই পদ্ধতি এবং অন্যদের মধ্যে একটি কার্যকরী পার্থক্য রয়েছে: এইভাবে পড়ার সময় ডিফল্ট মান নির্ধারণ করে (যেমন অ্যাসাইনমেন্টটি সর্বদা ব্লকের অভ্যন্তরে ঘটে থাকে)। উদাহরণ স্বরূপ:
h1 = Hash.new { |h, k| h[k] = [] }
h1[:x]
h1 #=> {:x=>[]}
h2 = Hash.new { [] }
h2[:x]
h2 #=> {}
অপরিবর্তনীয় উপায়
আপনি ভাবতে পারেন যে ঠিক কাজ Hash.new([])
করার সময় কেন কাজ করে না Hash.new(0)
। মূলটি হ'ল রুবিতে সংখ্যাসূচকগুলি অপরিবর্তনীয়, তাই আমরা স্বাভাবিকভাবেই কখনই সেগুলিকে জায়গায় স্থান দিতে পারি না। যদি আমরা আমাদের ডিফল্ট মানটিকে অপরিবর্তনীয় হিসাবে বিবেচনা করি, আমরা Hash.new([])
কেবল জরিমানাও ব্যবহার করতে পারি :
h = Hash.new([].freeze)
h[0] += ['a'] #=> ["a"]
h[1] += ['b'] #=> ["b"]
h[2] #=> []
h #=> {0=>["a"], 1=>["b"]}
তবে, এটি নোট করুন ([].freeze + [].freeze).frozen? == false
। সুতরাং, আপনি যদি নিশ্চিত করতে চান যে অপরিবর্তনশীলতা জুড়ে রক্ষা করা হয়েছে, তবে আপনাকে অবশ্যই নতুন অবজেক্টটি পুনরায় জমা করার জন্য যত্ন নিতে হবে।
উপসংহার
সমস্ত উপায়গুলির মধ্যে আমি ব্যক্তিগতভাবে "অপরিবর্তনীয় উপায়" পছন্দ করি — অনিবার্যতা সাধারণত বিষয়গুলি সম্পর্কে যুক্তি অনেক সহজ করে তোলে। সর্বোপরি, এটি একমাত্র পদ্ধতি যা লুকানো বা সূক্ষ্ম অপ্রত্যাশিত আচরণের কোনও সম্ভাবনা রাখে না। তবে, সর্বাধিক প্রচলিত এবং মূর্খতাপূর্ণ উপায় হ'ল "পরিবর্তনীয় উপায়"।
চূড়ান্ত হিসাবে, হ্যাশ ডিফল্ট মানগুলির এই আচরণটি রুবি কোয়ানসে লক্ষ্য করা যায় ।
† এটি কঠোরভাবে সত্য নয়, instance_variable_set
এটিকে বাইপাস করার মতো পদ্ধতিগুলি , তবে তাদের রূপান্তরকাজের জন্য অবশ্যই উপস্থিত থাকতে হবে কারণ এল-মানটি =
গতিশীল হতে পারে না।