हम Rubyists अपने हैश से प्यार करते हैं। लेकिन हैश की कुछ प्रसिद्ध खामियां हैं। जैसा कि रिचर्ड ने "Hashie Considered Harmful" में बताया, वे कभी-कभी बहुत लचीले हो सकते हैं - एक त्वरित टाइपो और आप उन कुंजियों को असाइन और संदर्भित कर सकते हैं जिनका आपका कभी इरादा नहीं था।
a = { type: "F150" } a[:typo] # nil
कुछ सामान्य हैश विकल्प
यदि आप वास्तविक संरचित डेटा संग्रहीत करने के लिए हैश का उपयोग कर रहे हैं, तो आप तय कर सकते हैं कि आपको वास्तव में लचीलेपन की आवश्यकता नहीं है। यह केवल आपको मुसीबत में डालने वाला है।
कुछ विकल्प हैं। कल्पना करें कि आपको XY निर्देशांक की एक जोड़ी संग्रहीत करने की आवश्यकता है। एक दृष्टिकोण एक क्लास को परिभाषित करना हो सकता है, जिसका एकमात्र काम XY निर्देशांक की एक जोड़ी को रखना है।
class PointClass # मैं क्लास के नाम को Class से समाप्त करने की सलाह नहीं देता :) attr_accessor :x, :y def initialize(args) @x = args.fetch(:x) @y = args.fetch(:y) end end point_class = PointClass.new(x: 1, y: 2) point_class.x # 1
चूंकि इस मामले में हमें केवल डेटा को एनकैप्सुलेट करने की आवश्यकता है, एक अधिक संक्षिप्त विकल्प Struct का उपयोग करना हो सकता है। यहाँ देखें कि यह कैसा दिखता है:
PointStruct = Struct.new(:x, :y) point_struct = PointStruct.new(1, 2) point_struct.x # 1
तीसरा विकल्प OpenStruct का उपयोग करना हो सकता है। OpenStruct एक Struct की तरह दिखता है, लेकिन आपको हैश की तरह मनमाने मान सेट करने देता है। यहाँ एक उदाहरण है:
point_os = OpenStruct.new(x: 1, y: 2) point_os.x # 1
प्रदर्शन निहितार्थ
[अपडेट 7/10/2015: ऐसा प्रतीत होता है कि मेरा बेंचमार्किंग स्क्रिप्ट हैश के प्रति अनुचित था। जैसा कि पैट्रिक हेल्म ने बताया, मैं उन्हें आरंभ करने के लिए एक अकुशल विधि का उपयोग कर रहा था। इसलिए कृपया हैश के परिणामों की अवहेलना करें। हालांकि OpenStruct के सुपर स्लो होने के बारे में मेरा मुख्य बिंदु अभी भी मान्य है। आप यहां मेरे बेंचमार्क स्क्रिप्ट में उनके परिवर्तन देख सकते हैं]
इन चार विकल्पों को देखकर, मुझे आश्चर्य हुआ कि प्रदर्शन निहितार्थ क्या थे। यह बहुत स्पष्ट है कि यदि आप केवल थोड़ा सा डेटा डील कर रहे हैं तो इनमें से कोई भी विकल्प काफी तेज है। लेकिन यदि आपके पास प्रोसेस करने के लिए हजारों या लाखों आइटम हैं, तो हैश बनाम OpenStruct बनाम स्ट्रक्ट बनाम क्लास का प्रदर्शन प्रभाव मायने रखने लग सकता है।
Honeybadger पर, हर सेकंड हमारे API को हजारों अपवाद रिपोर्ट किए जाते हैं, इसलिए इस तरह के प्रदर्शन निहितार्थ को समझना हमेशा हमारे दिमाग में रहता है।
तो, मैंने एक सरल बेंचमार्क स्क्रिप्ट लिखी। मुझे इस तरह के प्रयोगों के लिए benchmark-ips जेम का उपयोग करना पसंद है क्योंकि यह स्वचालित रूप से एक अच्छा सैंपल आकार निकालता है, और मानक विचलन की रिपोर्ट करता है।
आरंभीकरण
जब मैंने PointClass, PointStruct, Hash, और OpenStruct के लिए आरंभीकरण समय का बेंचमार्क किया, तो मैंने पाया कि PointClass और PointStruct स्पष्ट विजेता थे। वे OpenStruct की तुलना में लगभग 10x तेज थे, और हैश की तुलना में लगभग 2x तेज थे।

PointClass और PointStruct OpenStruct की तुलना में लगभग 10x तेज थे
ये परिणाम समझ में आते हैं। स्ट्रक्ट सबसे सरल हैं, इसलिए वे सबसे तेज हैं। OpenStruct सबसे जटिल है (यह हैश का एक रैपर है) इसलिए यह सबसे धीमा है। हालांकि गति में अंतर का परिमाण थोड़ा आश्चर्यजनक है।
इस प्रयोग को चलाने के बाद, मैं किसी भी कोड में OpenStruct का उपयोग करने में वास्तव में संकोच करूंगा जहां गति चिंता का विषय है। और मैं किसी भी हैश को प्रदर्शन-महत्वपूर्ण कोड में देखूंगा तो सावधान रहूंगा।
पढ़ें / लिखें
आरंभीकरण के विपरीत, सभी चार विकल्प मान सेट करने और एक्सेस करने के मामले में लगभग समान हैं।

पढ़ने और लिखने के बेंचमार्क Struct, क्लास, हैश और OpenStruct के बीच कोई बड़ा अंतर नहीं दिखाते
बेंचमार्किंग स्क्रिप्ट
यदि आप अपने सिस्टम पर बेंचमार्क चलाना चाहते हैं, तो आप नीचे दी गई स्क्रिप्ट का उपयोग कर सकते हैं। मैंने इसे OSX पर MRI 2.1 पर चलाया। यदि आप अन्य Ruby इंटरप्रेटर्स पर प्रदर्शन के बारे में उत्सुक हैं, तो माइकल कोहेन ने MRI 2.2, JRuby और अन्य के लिए परिणामों के साथ एक शानदार gist बनाया है।
require 'benchmark/ips' require 'ostruct' data = { x: 100, y: 200 } PointStruct = Struct.new(:x, :y) class PointClass attr_accessor :x, :y def initialize(args) @x = args.fetch(:x) @y = args.fetch(:y) end end puts "\n\nINITIALIZATION ==========" Benchmark.ips do |x| x.report("PointStruct") { PointStruct.new(100, 200) } x.report("PointClass") { PointClass.new(data) } x.report("Hash") { Hash.new.merge(data) } x.report("OpenStruct") { OpenStruct.new(data) } end puts "\n\nREAD ==========" point_struct = PointStruct.new(100, 200) point_class = PointClass.new(data) point_hash = Hash.new.merge(data) point_open_struct = OpenStruct.new(data) Benchmark.ips do |x| x.report("PointStruct") { point_struct.x } x.report("PointClass") { point_class.x } x.report("Hash") { point_hash.fetch(:x) } x.report("OpenStruct") { point_open_struct.x } end puts "\n\nWRITE ==========" Benchmark.ips do |x| x.report("PointStruct") { point_struct.x = 1 } x.report("PointClass") { point_class.x = 1 } x.report("Hash") { point_hash[:x] = 1 } x.report("OpenStruct") { point_open_struct.x = 1 } end