2011-02-18 8 views
440

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

attr_accessor :var 
attr_reader :var 
attr_writer :var 

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

+4

मैं केवल यही चाहता हूं कि वे इसे दस्तावेज करेंगे। http://api.rubyonrails.org/?q=attr_reader – Chloe

+22

@Chloe आप गलत जगह पर देख रहे हैं! यह एक रूबी विधि है, न कि * रेल *: http://www.ruby-doc.org/core-2.1.2/Module.html#method-i-attr_reader –

+0

संभव डुप्लिकेट [रूबी में attr \ _accessor क्या है ?] (http://stackoverflow.com/questions/4370960/what-is-attr-accessor-in-ruby) – sschuberth

उत्तर

642

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

class Person 
    attr_accessor :age 
    ... 
end 

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

class Person 
    attr_reader :age 
    ... 
end 

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

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

आप लिखते हैं:

attr_writer :age 

में अनुवाद किया जाता है यही कारण है कि:

def age=(value) 
    @age = value 
end 

यदि आप लिखना:

def age 
    @age 
end 
:

attr_reader :age 

में अनुवाद किया जाता है यही कारण है कि 10

यदि आप लिखना:

attr_accessor :age 

में अनुवाद किया जाता है यही कारण है कि:

def age=(value) 
    @age = value 
end 

def age 
    @age 
end 

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

+45

'attr_reader: a' बनाम लिखने के लिए एक * महत्वपूर्ण * प्रदर्शन लाभ भी है। 'एक डीएफ; एक वापसी; अंत 'http://confreaks.net/videos/427-rubyconf2010-zomg-why-is-this-code-so-slow – Nitrodist

+73

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

+0

इसे लिखने के लिए धन्यवाद इतना सटीक! – abhijit

10

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

+0

सरल और समझने योग्य –

13

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

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

20

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

9

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

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>' 

आप देख सकते हैं के रूप में नए चाबियाँ, परिवर्तन मूल्यों, eccetera जोड़ने के लिए, हैश @a से एक मुख्य/मान जोड़े हटाना संभव है। लेकिन आप एक नई ऑब्जेक्ट को इंगित नहीं कर सकते क्योंकि केवल पढ़ने के लिए आवृत्ति चर है।

+0

यह एक सहायक और उपयोगी भेद है। इसे शामिल करने के लिए धन्यवाद! :) –

संबंधित मुद्दे