रूबी वर्ग उदाहरण चर बनाम वर्ग चर


179

मैंने पढ़ा " कब रूबी उदाहरण चर सेट हो जाते हैं? " लेकिन मैं दो मन हूँ जब वर्ग उदाहरण चर का उपयोग करें।

कक्षा चर को एक वर्ग के सभी ऑब्जेक्ट द्वारा साझा किया जाता है, इंस्टेंस चर एक वस्तु से संबंधित होते हैं। यदि हमारे पास वर्ग चर हैं, तो कक्षा उदाहरण चर का उपयोग करने के लिए बहुत जगह नहीं बची है।

क्या कोई इन दोनों के बीच के अंतर को समझा सकता है और उन्हें कब इस्तेमाल करना है?

यहाँ एक कोड उदाहरण है:

class S
  @@k = 23
  @s = 15
  def self.s
    @s
  end
  def self.k
     @@k
  end

end
p S.s #15
p S.k #23

अब मैं समझता हूं, वंशानुक्रम श्रृंखला के साथ वर्ग उदाहरण चर नहीं पारित किए जाते हैं!

जवाबों:


276

एक वर्ग पर उदाहरण चर:

class Parent
  @things = []
  def self.things
    @things
  end
  def things
    self.class.things
  end
end

class Child < Parent
  @things = []
end

Parent.things << :car
Child.things  << :doll
mom = Parent.new
dad = Parent.new

p Parent.things #=> [:car]
p Child.things  #=> [:doll]
p mom.things    #=> [:car]
p dad.things    #=> [:car]

वर्ग चर:

class Parent
  @@things = []
  def self.things
    @@things
  end
  def things
    @@things
  end
end

class Child < Parent
end

Parent.things << :car
Child.things  << :doll

p Parent.things #=> [:car,:doll]
p Child.things  #=> [:car,:doll]

mom = Parent.new
dad = Parent.new
son1 = Child.new
son2 = Child.new
daughter = Child.new

[ mom, dad, son1, son2, daughter ].each{ |person| p person.things }
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]
#=> [:car, :doll]

एक वर्ग पर एक उदाहरण चर के साथ (उस वर्ग के एक उदाहरण पर नहीं) आप उप-वर्ग के बिना स्वचालित रूप से उन्हें (और इसके विपरीत) प्राप्त करने के बिना उस वर्ग के लिए कुछ सामान्य संग्रह कर सकते हैं। वर्ग चर के साथ, आपको self.classएक उदाहरण ऑब्जेक्ट से लिखने की सुविधा नहीं है , और (जब वांछित हो) आपको पूरे वर्ग पदानुक्रम में स्वचालित साझाकरण भी मिलता है।


इन्हें एक साथ एक एकल उदाहरण में विलय करना भी उदाहरणों पर उदाहरण चर को शामिल करता है:

class Parent
  @@family_things = []    # Shared between class and subclasses
  @shared_things  = []    # Specific to this class

  def self.family_things
    @@family_things
  end
  def self.shared_things
    @shared_things
  end

  attr_accessor :my_things
  def initialize
    @my_things = []       # Just for me
  end
  def family_things
    self.class.family_things
  end
  def shared_things
    self.class.shared_things
  end
end

class Child < Parent
  @shared_things = []
end

और फिर कार्रवाई में:

mama = Parent.new
papa = Parent.new
joey = Child.new
suzy = Child.new

Parent.family_things << :house
papa.family_things   << :vacuum
mama.shared_things   << :car
papa.shared_things   << :blender
papa.my_things       << :quadcopter
joey.my_things       << :bike
suzy.my_things       << :doll
joey.shared_things   << :puzzle
suzy.shared_things   << :blocks

p Parent.family_things #=> [:house, :vacuum]
p Child.family_things  #=> [:house, :vacuum]
p papa.family_things   #=> [:house, :vacuum]
p mama.family_things   #=> [:house, :vacuum]
p joey.family_things   #=> [:house, :vacuum]
p suzy.family_things   #=> [:house, :vacuum]

p Parent.shared_things #=> [:car, :blender]
p papa.shared_things   #=> [:car, :blender]
p mama.shared_things   #=> [:car, :blender]
p Child.shared_things  #=> [:puzzle, :blocks]  
p joey.shared_things   #=> [:puzzle, :blocks]
p suzy.shared_things   #=> [:puzzle, :blocks]

p papa.my_things       #=> [:quadcopter]
p mama.my_things       #=> []
p joey.my_things       #=> [:bike]
p suzy.my_things       #=> [:doll] 

@Phronz self.things और self.class.things के बीच अंतर क्या है जिसका आपने कोड में उल्लेख किया है?
सायबोर्ग

1
@cyborg ने वर्तमान स्कोप में self.thingsएक विधि thingsको संदर्भित किया (एक वर्ग के उदाहरण के मामले में, यह उदाहरण की विधि होगी), जहां वर्तमान स्कोप के वर्ग से self.class.thingsएक thingsविधि को संदर्भित करता है (फिर एक वर्ग के उदाहरण के मामले में इसका मतलब होगा वर्ग विधि)।
भित्तिचित्र

सुंदर व्याख्या।
aliahme922

30

मेरा मानना ​​है कि मुख्य (केवल) अलग है विरासत:

class T < S
end

p T.k
=> 23

S.k = 24
p T.k
=> 24

p T.s
=> nil

वर्ग चर सभी "वर्ग उदाहरण" (यानी उपवर्ग) द्वारा साझा किए जाते हैं, जबकि वर्ग उदाहरण चर केवल उस वर्ग के लिए विशिष्ट होते हैं। लेकिन यदि आप कभी भी अपनी कक्षा का विस्तार करने का इरादा नहीं रखते हैं, तो अंतर पूरी तरह से अकादमिक है।


1
बस यही फर्क नहीं है। "साझा" बनाम "उदाहरण" विरासत से आगे बढ़ता है। यदि आप उदाहरण प्राप्त करते हैं तो आपको मिलेगा S.new.s => nilऔर S.new.k => 23
आंद्रे फिगयेरिडो

27

स्रोत

उदाहरण के तरीकों की उपलब्धता

  • वर्ग उदाहरण चर केवल वर्ग विधियों के लिए उपलब्ध हैं और विधियों को उदाहरण के लिए नहीं।
  • कक्षा चर उदाहरण के तरीकों और वर्ग विधियों दोनों के लिए उपलब्ध हैं।

Inheritability

  • वंशानुक्रम श्रृंखला में श्रेणी उदाहरण चर खो जाते हैं।
  • वर्ग चर नहीं हैं।
class Vars

  @class_ins_var = "class instance variable value"  #class instance variable
  @@class_var = "class variable value" #class  variable

  def self.class_method
    puts @class_ins_var
    puts @@class_var
  end

  def instance_method
    puts @class_ins_var
    puts @@class_var
  end
end

Vars.class_method

puts "see the difference"

obj = Vars.new

obj.instance_method

class VarsChild < Vars


end

VarsChild.class_method

15

जैसा कि दूसरों ने कहा, वर्ग चर किसी दिए गए वर्ग और उसके उपवर्गों के बीच साझा किए जाते हैं। वर्ग उदाहरण चर बिल्कुल एक वर्ग के हैं; इसके उपवर्ग अलग-अलग हैं।

यह व्यवहार क्यों मौजूद है? ठीक है, रूबी में सब कुछ एक वस्तु है - यहां तक ​​कि कक्षाएं भी। इसका मतलब यह है कि प्रत्येक वर्ग के पास Class(या बल्कि, एक उपवर्ग Class) की एक वस्तु होती है। (जब आप कहते हैं class Foo, आप वास्तव में एक निरंतर की घोषणा कर रहे हैंFoo और एक वर्ग वस्तु को निर्दिष्ट ।) और प्रत्येक रूबी ऑब्जेक्ट में उदाहरण चर हो सकते हैं, इसलिए कक्षा ऑब्जेक्ट में उदाहरण चर भी हो सकते हैं।

परेशानी यह है कि उदाहरण के लिए, क्लास ऑब्जेक्ट पर वैरिएबल वास्तव में उस तरह का व्यवहार नहीं करते हैं जैसा आप आमतौर पर क्लास वेरिएबल्स के व्यवहार के लिए करते हैं। आप आमतौर पर चाहते हैं कि सुपरक्लास में परिभाषित एक वर्ग चर को उसके उपवर्गों के साथ साझा किया जाए, लेकिन यह नहीं है कि कैसे उदाहरण चर काम करते हैं- उपवर्ग का अपना वर्ग वस्तु होता है, और उस वर्ग वस्तु का अपना उदाहरण चर होता है। इसलिए वे अलग-अलग वर्ग चर पेश करते हैं जो आप चाहते हैं कि व्यवहार के साथ हो।

दूसरे शब्दों में, वर्ग उदाहरण चर रूबी के डिजाइन की दुर्घटना की तरह हैं। जब तक आप विशेष रूप से वे नहीं जानते कि आप क्या खोज रहे हैं, तब तक आपको उनका उपयोग नहीं करना चाहिए।


तो जावा में स्थिर चर की तरह वर्ग चर है?
किक करें

3

आधिकारिक रूबी सामान्य प्रश्न: वर्ग चर और वर्ग उदाहरण चर के बीच अंतर क्या है?

मुख्य अंतर विरासत के विषय में व्यवहार है: वर्ग चर एक वर्ग और उसके सभी उपवर्गों के बीच साझा किए जाते हैं, जबकि वर्ग उदाहरण चर केवल एक विशिष्ट वर्ग के होते हैं।

वर्ग चर को किसी तरह से वैश्विक चर के रूप में देखा जा सकता है, जो विरासत वंशानुक्रम के संदर्भ में वैश्विक चर के साथ आने वाली सभी समस्याओं के साथ है। उदाहरण के लिए, एक वर्ग चर (दुर्घटनावश) अपने सभी उपवर्गों को प्रभावित कर सकता है, अन्य सभी वर्गों को प्रभावित करता है:

class Woof

  @@sound = "woof"

  def self.sound
    @@sound
  end
end

Woof.sound  # => "woof"

class LoudWoof < Woof
  @@sound = "WOOF"
end

LoudWoof.sound  # => "WOOF"
Woof.sound      # => "WOOF" (!)

या, पूर्वज वर्ग को बाद में फिर से खोला जा सकता है और बदल दिया जा सकता है, संभवतः आश्चर्यजनक प्रभाव के साथ:

class Foo

  @@var = "foo"

  def self.var
    @@var
  end
end

Foo.var  # => "foo" (as expected)

class Object
  @@var = "object"
end

Foo.var  # => "object" (!)

इसलिए, जब तक आप वास्तव में नहीं जानते कि आप क्या कर रहे हैं और स्पष्ट रूप से इस तरह के व्यवहार की आवश्यकता है, तो आपको बेहतर श्रेणी उदाहरण चर का उपयोग करना चाहिए।


2

C ++ बैकग्राउंड वाले लोगों के लिए, आप C ++ समकक्ष की तुलना में दिलचस्पी ले सकते हैं:

class S
{
private: // this is not quite true, in Ruby you can still access these
  static int    k = 23;
  int           s = 15;

public:
  int get_s() { return s; }
  static int get_k() { return k; }

};

std::cerr << S::k() << "\n";

S instance;
std::cerr << instance.s() << "\n";
std::cerr << instance.k() << "\n";

जैसा कि हम देख सकते हैं, kएक staticचर की तरह है। यह एक वैश्विक चर की तरह 100% है, सिवाय इसके कि यह वर्ग के स्वामित्व में है ( सही होने के लिए स्कोप किया गया)। इससे समान रूप से नामित चर के बीच झड़पों से बचना आसान हो जाता है। किसी भी वैश्विक चर की तरह, उस चर का सिर्फ एक उदाहरण है और इसे संशोधित करना हमेशा सभी द्वारा दिखाई देता है।

दूसरी ओर, sएक वस्तु विशिष्ट मूल्य है। प्रत्येक वस्तु के मूल्य का अपना उदाहरण है। C ++ में, आपको उस वैरिएबल तक पहुंच के लिए एक उदाहरण बनाना होगा। रूबी में, वर्ग परिभाषा अपने आप में कक्षा का एक उदाहरण है (जावास्क्रिप्ट में, इसे एक प्रोटोटाइप कहा जाता है), इसलिए आप sअतिरिक्त तात्कालिकता के बिना कक्षा से पहुंच सकते हैं । वर्ग उदाहरण को संशोधित किया जा सकता है, लेकिन sप्रत्येक उदाहरण (प्रत्येक प्रकार की वस्तु S) के लिए विशिष्ट होने वाला है । तो एक को संशोधित करने से दूसरे में मूल्य नहीं बदलेगा।


1

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

class C
  @@c = 'c'
  def self.c_val
    @@c
  end
end

C.c_val
 => "c" 

class D < C
end

D.instance_eval do 
  def change_c_val
    @@c = 'd'
  end
end
 => :change_c_val 

D.change_c_val
(irb):12: warning: class variable access from toplevel
 => "d" 

C.c_val
 => "d" 

रेल एक उपयोगी विधि का परिचय देती है जिसे class_attribute कहा जाता है। जैसा कि नाम से ही स्पष्ट है, यह एक वर्ग-स्तरीय विशेषता घोषित करता है जिसका मूल्य उपवर्गों द्वारा अंतर्निहित है। Class_attribute मान को सिंगलटन और इंस्टेंस दोनों तरीकों से एक्सेस किया जा सकता है, जैसा कि क्लास उदाहरण चर के साथ होता है। हालाँकि, Rails में class_attribute के साथ बहुत बड़ा लाभ उपवर्गों का अपना मूल्य बदल सकता है और यह मूल वर्ग को प्रभावित नहीं करेगा।

class C
  class_attribute :c
  self.c = 'c'
end

 C.c
 => "c" 

class D < C
end

D.c = 'd'
 => "d" 

 C.c
 => "c" 

अच्छी कॉल, मैंने पहले इसका इस्तेमाल नहीं किया था। यह काम करने लगता है, हालांकि आपको self.हर बार जब आप विशेषता का उपयोग करना चाहते हैं, तो इसे सुनिश्चित करने की आवश्यकता होती हैc , उदाहरण केself.c । डॉक्स का कहना है कि एक default:पैरामीटर पारित किया जा सकता है, class_attributeलेकिन यह मेरे द्वारा बताए गए बिंदु के कारण काम नहीं करता है self
डेस

जब आप कहते हैं "जबकि यह तुरंत वर्ग उदाहरण चर का उपयोग करने के लिए उपयोगी लग सकता है", मुझे लगता है कि आप "वर्ग चर" का मतलब है, न कि "वर्ग उदाहरण चर" सही? ( Ruby-lang.org/en/documentation/faq/8/ देखें )
कीथ बेनेट

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