रूबी के attr_accessor, attr_reader और attr_writer का उपयोग क्यों करें?


517

रूबी के पास इस तरह की कुंजी का उपयोग करके उदाहरण चर साझा करने का आसान और सुविधाजनक तरीका है

attr_accessor :var
attr_reader :var
attr_writer :var

मैं क्यों चुनूंगा attr_readerया attr_writerअगर मैं बस इस्तेमाल कर सकता हूं attr_accessor? क्या प्रदर्शन जैसा कुछ है (जिस पर मुझे संदेह है)? मुझे लगता है कि एक कारण है, अन्यथा वे इस तरह की चाबी नहीं बनाते।


जवाबों:


746

आप अपने कोड को पढ़ने वाले किसी व्यक्ति के लिए अपने इरादे को संप्रेषित करने के लिए अलग-अलग एक्सेसरों का उपयोग कर सकते हैं, और उन कक्षाओं को लिखना आसान बना सकते हैं जो सही ढंग से काम करेंगे चाहे उनके सार्वजनिक एपीआई को कैसे बुलाया जाए।

class Person
  attr_accessor :age
  ...
end

यहाँ, मैं देख सकता हूँ कि मैं उम्र पढ़ और लिख सकता हूँ।

class Person
  attr_reader :age
  ...
end

यहाँ, मैं देख सकता हूँ कि मैं केवल उम्र पढ़ सकता हूँ। कल्पना कीजिए कि यह इस वर्ग के निर्माता द्वारा निर्धारित किया गया है और उसके बाद स्थिर रहता है। यदि उम्र के लिए एक उत्परिवर्ती (लेखक) थे और वर्ग को यह मानते हुए लिखा गया था कि एक बार सेट होने पर, कोई बदलाव नहीं होता है, तो कोड बग से उस उत्परिवर्ती को बुला सकता है।

लेकिन पर्दे के पीछे क्या हो रहा है?

यदि आप लिखते हैं:

attr_writer :age

इसमें अनुवाद किया गया है:

def age=(value)
  @age = value
end

यदि आप लिखते हैं:

attr_reader :age

इसमें अनुवाद किया गया है:

def age
  @age
end

यदि आप लिखते हैं:

attr_accessor :age

इसमें अनुवाद किया गया है:

def age=(value)
  @age = value
end

def age
  @age
end

यह जानते हुए कि, इसके बारे में सोचने का एक और तरीका है: यदि आपके पास attr _... हेल्पर्स नहीं थे, और एक्सेसर्स को स्वयं लिखना था, तो क्या आप अपनी कक्षा की तुलना में किसी भी अधिक एक्सेसर्स को लिखेंगे? उदाहरण के लिए, यदि उम्र को केवल पढ़ने की आवश्यकता है, तो क्या आप इसे लिखने के लिए एक विधि भी लिखेंगे?


53
बनाम confreaks.net/videos/… लिखने के लिए एक महत्वपूर्ण प्रदर्शन लाभ भी हैattr_reader :adef a; return a; end
नाइट्रोडिस्ट

83
@ नाइट्रोडिस्ट, दिलचस्प। रूबी 1.8.7 के लिए, attr_readerपरिभाषित accesor उस समय का 86% लेता है जो मैन्युअल रूप से परिभाषित एक्सेसर करता है। रूबी 1.9.0 के लिए, attr_readerपरिभाषित एक्सेसर उस समय का 94% लेता है जो मैन्युअल रूप से परिभाषित एक्सेसर करता है। मेरे सभी परीक्षणों में, हालांकि, एक्सेसर तेज़ हैं: एक एक्सेसर लगभग 820 नैनोसेकंड (रूबी 1.8.7) या 440 नैनोसेकंड (रूबी 1.9) लेता है। उन गति पर, आपको attr_accessorएक सेकंड में समग्र रनटाइम में सुधार करने के लिए प्रदर्शन के लाभ के लिए लाखों बार एक एक्सेसर को कॉल करना होगा।
वेन कॉनराड

22
"संभवतः, यह इस वर्ग के निर्माता द्वारा निर्धारित किया गया है और स्थिर रहता है।" यह सटीक नहीं है। पाठकों के साथ इंस्टेंस चर अक्सर बदल सकते हैं। हालांकि यह इरादा है कि उनके मूल्यों को केवल कक्षा द्वारा निजी तौर पर बदल दिया जाए।
mlibby

11
आप 2 से अधिक विशेषताओं को जोड़ने के लिए "," का उपयोग कर सकते हैं, जैसे:attr_accessor :a, :b
एंड्रयू_ 1510

2
इन सभी वर्षों के बाद क्या मूल्य है: github.com/JuanitoFatas/… रूबी 2.2.0 attr_ * पर नवीनतम बेंचमार्क के अनुसार गेटर्स और सेटर से तेज हैं।
मोली

25

उपरोक्त सभी उत्तर सही हैं; attr_readerऔर attr_writerउन तरीकों को मैन्युअल रूप से लिखने की तुलना में अधिक सुविधाजनक हैं जिनके लिए वे शॉर्टहैंड हैं। इसके अलावा वे विधि परिभाषा लिखने की तुलना में खुद को बेहतर प्रदर्शन प्रदान करते हैं। अधिक जानकारी के लिए आरोन पैटरसन द्वारा इस वार्ता ( पीडीएफ ) से आगे 152 स्लाइड देखें ।


16

किसी वस्तु की सभी विशेषताओं को सीधे वर्ग के बाहर से निर्धारित नहीं किया जाता है। आपके सभी उदाहरण चर के लिए लेखकों का होना आमतौर पर कमजोर अतिक्रमण और एक चेतावनी का संकेत है जो आप अपनी कक्षाओं के बीच बहुत अधिक युग्मन का परिचय दे रहे हैं।

एक व्यावहारिक उदाहरण के रूप में: मैंने एक डिज़ाइन प्रोग्राम लिखा है जहाँ आप कंटेनरों के अंदर आइटम डालते हैं। आइटम था attr_reader :container, लेकिन यह एक लेखक की पेशकश करने के लिए कोई मतलब नहीं था, क्योंकि आइटम के कंटेनर को बदलने का एकमात्र समय तब होता है जब इसे एक नए में रखा जाता है, जिसमें स्थिति की जानकारी भी आवश्यक होती है।


16

यह समझना महत्वपूर्ण है कि एक्सेसर्स वेरिएबल तक पहुंच को प्रतिबंधित करते हैं, लेकिन उनकी सामग्री को नहीं। रूबी में, कुछ अन्य OO भाषाओं की तरह, प्रत्येक चर उदाहरण के लिए एक संकेतक है। इसलिए, यदि आपके पास हैश का एक गुण है, उदाहरण के लिए, और आपने इसे "केवल पढ़ने के लिए" सेट किया है तो आप हमेशा इसकी सामग्री को बदल सकते हैं, लेकिन पॉइंटर की सामग्री को नहीं। इसे देखो:

irb(main):024:0> class A
irb(main):025:1> attr_reader :a
irb(main):026:1> def initialize
irb(main):027:2> @a = {a:1, b:2}
irb(main):028:2> end
irb(main):029:1> end
=> :initialize
irb(main):030:0> a = A.new
=> #<A:0x007ffc5a10fe88 @a={:a=>1, :b=>2}>
irb(main):031:0> a.a
=> {:a=>1, :b=>2}
irb(main):032:0> a.a.delete(:b)
=> 2
irb(main):033:0> a.a
=> {:a=>1}
irb(main):034:0> a.a = {}
NoMethodError: undefined method `a=' for #<A:0x007ffc5a10fe88 @a={:a=>1}>
        from (irb):34
        from /usr/local/bin/irb:11:in `<main>'

जैसा कि आप देख सकते हैं कि हश @ ए से एक कुंजी / मूल्य जोड़ी को हटाना संभव है, क्योंकि नई कुंजी, मूल्य बदलें, एक्केटेरा जोड़ें। लेकिन आप एक नई वस्तु की ओर संकेत नहीं कर सकते क्योंकि एक पढ़ने के लिए केवल उदाहरण चर है।


13

आप हमेशा नहीं चाहते हैं कि आपकी आवृत्ति चर वर्ग के बाहर से पूरी तरह से सुलभ हो। ऐसे बहुत से मामले हैं जहां एक इंस्टेंस वेरिएबल को पढ़ने की अनुमति देना समझ में आता है, लेकिन इसे लिखना संभव नहीं है (उदाहरण के लिए एक मॉडल जो केवल-पढ़ने के लिए स्रोत से डेटा पुनर्प्राप्त करता है)। ऐसे मामले हैं जहां आप विपरीत चाहते हैं, लेकिन मैं ऐसा कोई भी नहीं सोच सकता हूं जो मेरे सिर के ऊपर से वंचित न हों।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.