2009-05-05 16 views
61
class Hello 
@hello = "hello" 
    def display 
     puts @hello 
    end 
end 

h = Hello.new 
h.display 

मैंने उपरोक्त वर्ग बनाया है। यह कुछ भी प्रिंट नहीं करता है। मैंने सोचा कि आवृत्ति चर @hello कक्षा घोषणा के दौरान सेट किया गया था। लेकिन जब मैं डिस्प्ले विधि को कॉल करता हूं तो आउटपुट 'शून्य' होता है। ऐसा करने का सही तरीका क्या है?रुबी इंस्टेंस चर सेट कब करते हैं?

class Hello 
    def initialize 
     @hello = "hello" 
    end 
    def display 
     puts @hello 
    end 
end 

h = Hello.new 
h.display 

उत्तर

88

उदाहरण चर थोड़ा भ्रमित जब पहली रूबी सीखने हो सकता है, खासकर यदि आप जावा की तरह एक और OO भाषा के आदी रहे हैं ।

आप बस एक आवृत्ति चर घोषित नहीं कर सकते हैं।

रूबी में इंस्टेंस चर के बारे में जानने के लिए सबसे महत्वपूर्ण चीजों में से एक, @ साइन उपसर्ग के साथ नोटेशन के अलावा, वे पहली बार जीवन में वसंत करते हैं जब उन्हें पर सौंपा जाता है।

class Hello 
    def create_some_state 
    @hello = "hello" 
    end 
end 

h = Hello.new 
p h.instance_variables 

h.create_some_state 
p h.instance_variables 

# Output 
[] 
["@hello"] 

आप एक वस्तु के सभी उदाहरण चर सूची विधि Object#instance_variables उपयोग कर सकते हैं।

आप सामान्य रूप से "घोषणा" करते हैं और आरंभिक विधि में सभी इंस्टेंस चर प्रारंभ करते हैं। सार्वजनिक रूप से उपलब्ध होने वाले आवृत्ति चर को स्पष्ट रूप से दस्तावेज करने का एक और तरीका मॉड्यूल विधियों attr_accessor (पढ़ें/लिखें), attr_writer (लिखें) और attr_reader (पढ़ें) का उपयोग करना है। ये विधियां सूचीबद्ध इंस्टेंस चर के लिए विभिन्न एक्सेसर विधियों को संश्लेषित करेंगी।

class Hello 
    attr_accessor :hello 
end 

h = Hello.new 
p h.instance_variables 

h.hello = "hello" 
p h.instance_variables 

# Output 
[] 
["@hello"] 

उदाहरण चर अभी भी जब तक यह संश्लेषित Hello#hello= विधि का उपयोग करने के लिए असाइन किया गया है नहीं बनाया गया है।

एक अन्य महत्वपूर्ण मुद्दा, जैसे कि वर्णित वर्णन, यह है कि आपको कक्षा घोषित करते समय सक्रिय विभिन्न संदर्भों से अवगत होना चाहिए। बाहरी वर्ग में डिफ़ॉल्ट रिसीवर (स्वयं) कक्षा को घोषित करते समय वह ऑब्जेक्ट होगा जो कक्षा का प्रतिनिधित्व करता है। इसलिए कक्षा कोड पर @hello को असाइन करते समय आपका कोड पहले क्लास इंस्टेंस चर बना देगा।

अंदर तरीकों स्वयं, वस्तु, जिस पर विधि शुरू हो जाती है हो जाएगा इसलिए आप (ध्यान दें कि यह पूरी तरह है वस्तु है, जो मौजूद नहीं करता है में नाम @hello साथ एक उदाहरण चर के मूल्य मुद्रित करने के लिए कोशिश कर रहे हैं एक गैर मौजूदा आवृत्ति चर पढ़ने के लिए कानूनी)।

+2

आप कहते हैं, "वे पहली बार जीवन में वसंत करते हैं जब उन्हें सौंपा जाता है" फिर भी ओपी ने आपके उदाहरण के मुकाबले पहले (स्पष्ट) असाइनमेंट के साथ एक उदाहरण दिखाया, और अनुभव की गई समस्या यह है कि कहा गया चर वैसा ही जीवन में नहीं उभरा था। – kaleidic

+1

@ kaleidic बिल्कुल। मैं इस उत्तर पर अपवॉट्स की संख्या पर थोड़ा परेशान हूं जो ओपी के प्रश्न को संबोधित नहीं करता है। वास्तव में, क्लास इंस्टेंस वैरिएबल '@ हैलो' * * उदाहरण कोड के पंक्ति 2 पर जीवन में वसंत करता है, लेकिन समस्या यह है कि वह चर नहीं है जो पंक्ति 4 को संदर्भित करता है। अधिक जानकारी के लिए नीचे मेरा जवाब देखें। –

+0

क्षमा करें, आप वास्तव में अंत में प्रश्न का उत्तर देते हैं, जिसे मैंने पहले पढ़ने पर याद किया। –

42

आप एक initialize विधि जोड़ने की जरूरत है।

यह वर्ग वस्तु जो निरंतर Hello अंक का एक उदाहरण चर है। तकनीकी तौर पर अपने self अपने वर्तमान वर्ग की वस्तु के लिए सेट है, और @variables अपने वर्तमान self से संबंधित (और वर्ग Class का एक उदाहरण है।)

, जब आप class दायरे के भीतर कर रहे हैं,। लड़का मैं इन चीजों को समझाने में चूसता हूं।

आप this collection of $5-each screencasts from The Pragmatic Programmers देख कर यह सब और भी बहुत कुछ आप के लिए स्पष्ट किया प्राप्त कर सकते हैं।

(या आप स्पष्टीकरण के लिए यहाँ पूछ सकते हैं और मैं अद्यतन करने के लिए कोशिश करेंगे।) माणिक में

21

पहले @hello अपने कोड में एक वर्ग उदाहरण चर कहा जाता है:

+0

एक अच्छा [लेख] (http://www.railstips.org/blog/archives/2006/11/18/class-and-instance-variables-in-ruby/) कक्षा-स्तर के आवृत्ति चर पर विस्तार से। –

9

"रूबी प्रोग्रामिंग भाषा" पुस्तक में एक स्पष्ट विवरण है, इसे पढ़ें बहुत उपयोगी होगा। मैं इसे यहाँ (अध्याय 7.1.16 से) पेस्ट:

एक उदाहरण एक वर्ग परिभाषा के अंदर लेकिन एक उदाहरण विधि परिभाषा के बाहर इस्तेमाल किया चर एक वर्ग उदाहरण चर है।

class Point 
    # Initialize our class instance variables in the class definition itself 
    @n = 0    # How many points have been created 
    @totalX = 0   # The sum of all X coordinates 
    @totalY = 0   # The sum of all Y coordinates 

    def initialize(x,y) # Initialize method 
     @x,@y = x, y  # Sets initial values for instance variables 
    end 

    def self.new(x,y) # Class method to create new Point objects 
     # Use the class instance variables in this class method to collect data 
     @n += 1   # Keep track of how many Points have been created 
     @totalX += x  # Add these coordinates to the totals 
     @totalY += y 

     super    # Invoke the real definition of new to create a Point 
        # More about super later in the chapter 
    end 

    # A class method to report the data we collected 
    def self.report 
     # Here we use the class instance variables in a class method 
     puts "Number of points created: #@n" 
     puts "Average X coordinate: #{@totalX.to_f/@n}" 
     puts "Average Y coordinate: #{@totalY.to_f/@n}" 
    end 
end 

......

क्योंकि वर्ग उदाहरण चर वर्ग वस्तुओं की सिर्फ उदाहरण चर हैं, हम उनके लिए एक्सेसर तरीकों बनाने के लिए attr, attr_reader, और attr_accessor उपयोग कर सकते हैं ।

class << self 
    attr_accessor :n, :totalX, :totalY 
end 
इन accessors परिभाषित है, हम के रूप में Point.n, Point.totalX, और Point.totalY हमारे कच्चे डेटा का उल्लेख कर सकते के साथ

1

मैं भी वर्ग चर जो लगी होती हैं पर देख रहे हैं सलाह देते हैं "@@" - यहाँ आप को दिखाने के लिए कैसे वर्ग और उदाहरण वार्स अलग हैं कुछ नमूना कोड:

class Vars 
    @@classvar="foo" 
    def test 
    @instancevar="bar" 
    end 
    def Vars.show 
    puts "classvar: #{@@classvar}" 
    puts "instancevar: #{@instancevar}" 
    end 
    def instance_show 
    puts "classvar: #{@@classvar}" 
    puts "instancevar: #{@instancevar}" 

    end 
end 

# only shows classvar since we don't have an instance created 
Vars::show 
# create a class instance 
vars = Vars.new 
# instancevar still doesn't show b/c it hasn't been initialized 
vars.instance_show 
# initialize instancevar 
vars.test 
# now instancevar shows up as we expect 
vars.instance_show 
4

मैं भूल गया है कि वहाँ रुबी में एक "वर्ग आवृत्ति चर" अवधारणा थी। किसी भी मामले में, ओपी की समस्या परेशान लग रही थी, और वास्तव में किसी भी उत्तर में संबोधित नहीं किया गया था, कोच के जवाब में संकेत के अलावा: यह दायरे की समस्या है। (संपादन पर जोड़ा गया: असल में, श्रीस का जवाब अंत में इस बिंदु को संबोधित करता है, लेकिन मुझे लगता है कि यह उत्तर समस्या को समझने के लिए उपयोगी हो सकता है।)

जहां कक्षा में यह कहा जाता है के आधार पर एक उदाहरण चर या एक वर्ग उदाहरण चर, करने के लिए करने के लिए या तो: रूबी वर्ग, एक चर नाम @ के साथ शुरू दो चर में से एक का उल्लेख कर सकते। यह एक काफी सूक्ष्म गोचा है।

एक उदाहरण बिंदु को स्पष्ट करेगा।

class T 

    @@class_variable = "BBQ" 
    @class_instance_variable_1 = "WTF" 
    @class_instance_variable_2 = "LOL" 

    def self.class_method 
    puts "@@class_variable   == #{@@class_variable   || 'nil'}" 
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}" 
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}" 
    puts "@instance_variable   == #{@instance_variable   || 'nil'}" 
    end 

    def initialize 
    @instance_variable = "omg" 
    # The following line does not assign a value to the class instance variable, 
    # but actually declares an instance variable withthe same name! 
    @class_instance_variable_1 = "wtf" 
    puts "@@class_variable   == #{@@class_variable   || 'nil'}" 
    # The following two lines do not refer to the class instance variables, 
    # but to the instance variables with the same names. 
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}" 
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}" 
    puts "@instance_variable   == #{@instance_variable   || 'nil'}" 
    end 

    def instance_method 
    puts "@@class_variable   == #{@@class_variable   || 'nil'}" 
    # The following two lines do not refer to the class instance variables, 
    # but to the instance variables with the same names. 
    puts "@class_instance_variable_1 == #{@class_instance_variable_1 || 'nil'}" 
    puts "@class_instance_variable_2 == #{@class_instance_variable_2 || 'nil'}" 
    puts "@instance_variable   == #{@instance_variable   || 'nil'}" 
    end 

end 

मैं मैं क्या सोचा था कि वे थे के अनुसार चर नाम है, कि हालांकि नहीं करने के लिए पता चला है हमेशा ऐसा होने के लिए: यह एक छोटा सा रूबी परीक्षण वर्ग (सभी कोड आईआरबी में परीक्षण किया गया) है

irb> T.class_method 
@@class_variable   == BBQ 
@class_instance_variable_1 == WTF # the value of the class instance variable 
@class_instance_variable_2 == LOL # the value of the class instance variable 
@instance_variable   == nil # does not exist in the class scope 
=> nil 

irb> t = T.new 
@@class_variable   == BBQ 
@class_instance_variable_1 == wtf # the value of the instance variable 
@class_instance_variable_2 == nil # the value of the instance variable 
@instance_variable   == omg 
=> #<T:0x000000015059f0 @instance_variable="omg", @class_instance_variable_1="wtf"> 

irb> t.instance_method 
@@class_variable   == BBQ 
@class_instance_variable_1 == wtf # the value of the instance variable 
@class_instance_variable_2 == nil # the value of the instance variable 
@instance_variable   == omg 
=> nil 

irb> T.class_method 
@@class_variable   == BBQ 
@class_instance_variable_1 == WTF # the value of the class instance variable 
@class_instance_variable_2 == LOL # the value of the class instance variable 
@instance_variable   == nil # does not exist in the class scope 
=> nil 

@@class_variable और @instance_variable हमेशा व्यवहार करते हैं जैसा कि आप उम्मीद करेंगे: पूर्व वर्ग स्तर पर परिभाषित किया गया है, और चाहे किसी वर्ग विधि में या किसी उदाहरण विधि में संदर्भित किया गया हो, तो इसे शीर्ष पर असाइन किया गया मान रखता है। उत्तरार्द्ध केवल कक्षा T के किसी ऑब्जेक्ट में एक मान प्राप्त करता है, इसलिए कक्षा विधि में, यह एक अज्ञात चर को संदर्भित करता है जिसका मान nil है।

class_method नाम की क्लास विधि @@class_variable के मानों को आउटपुट करती है और दो @class_instance_variable एस अपेक्षा की जाती है, जैसा कक्षा के शीर्ष पर शुरू किया गया है। हालांकि, उदाहरण के तरीकों में initialize और instance_method, एक ही नाम की अलग चर एक्सेस किया जाता है, वह है, उदाहरण चर, नहीं वर्ग उदाहरण चर

आप देख सकते हैं कि initialize विधि में काम, वर्ग उदाहरण चर @class_instance_variable_1 को प्रभावित नहीं किया क्योंकि class_method के बाद कॉल अपने पुराने मूल्य, "WTF" आउटपुट। इसके बजाय, विधि initializeने एक नया इंस्टेंस वैरिएबल घोषित किया, एक नामित (भ्रामक रूप से) @class_instance_variable_1। इसे सौंपा गया मान, "wtf", विधियों initialize और instance_method द्वारा आउटपुट है।

चर @class_instance_variable_2 उदाहरण के कोड में वास्तविक समस्या में चर @hello के बराबर है: यह घोषणा की और एक वर्ग उदाहरण चर के रूप में प्रारंभ है, लेकिन जब एक उदाहरण विधि है कि नाम के एक चर को संदर्भित करता है, यह वास्तव में देखता है एक उदाहरण एक ही नाम के साथ परिवर्तनीय - जिसे कभी घोषित नहीं किया गया था, इसलिए इसका मूल्य शून्य है।

+0

केवल यह जवाब समझ में आता है :) – InQusitive

+0

@InQusitive Glad मदद की खुशी! –

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