रूबी में @@ वेरिएबल का क्या अर्थ है?


162

रूबी वैरिएबल संकेतों ( @@) पर डबल के साथ पहले क्या हैं ? एक चिह्न के साथ पहले वाले चर की मेरी समझ यह है कि यह एक उदाहरण चर है, जैसे PHP में:

PHP संस्करण

class Person {

    public $name;

    public function setName($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

रूबी बराबर

class Person

    def set_name(name)
        @name = name
    end

    def get_name()
        @name
    end
end

साइन पर डबल का क्या @@अर्थ है, और यह साइन पर एकल से कैसे भिन्न होता है?


103
मुझे नहीं पता, लेकिन मुझे लग रहा है कि यह मुझे घूर रहा है। मैं अब रूबी में कोड करने से थोड़ा डरता हूं ...
corsiKa

2
टीएल; डीआर फॉर द पब्लिक: 100 में से 99 बार, मैं "क्लास इंस्टेंस" वेरिएबल्स ( @अंदरूनी selfतरीकों) का उपयोग करूंगा न कि क्लास वेरिएबल ( @@)। नीचे दिए गए उत्तरों में कारणों की लिटनी देखें।
वॉट्सएनाबॉक्स

जवाबों:


240

एक चर के साथ उपसर्ग @एक उदाहरण चर है , जबकि एक के साथ उपसर्ग @@एक वर्ग चर है । निम्नलिखित उदाहरण देखें; इसका उत्पादन putsलाइनों के अंत में टिप्पणियों में है :

class Test
  @@shared = 1

  def value
    @@shared
  end

  def value=(value)
    @@shared = value
  end
end

class AnotherTest < Test; end

t = Test.new
puts "t.value is #{t.value}" # 1
t.value = 2
puts "t.value is #{t.value}" # 2

x = Test.new
puts "x.value is #{x.value}" # 2

a = AnotherTest.new
puts "a.value is #{a.value}" # 2
a.value = 3
puts "a.value is #{a.value}" # 3
puts "t.value is #{t.value}" # 3
puts "x.value is #{x.value}" # 3

आप देख सकते हैं कि @@sharedकक्षाओं के बीच साझा किया गया है; एक की आवृत्ति में मान सेट करने से उस वर्ग और यहां तक ​​कि बाल वर्गों के अन्य सभी उदाहरणों के लिए मान बदल जाता है, जहां एक चर नाम @shared, एक के साथ @नहीं होगा।

[अपडेट करें]

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

class Polygon
  class << self
    attr_accessor :sides
  end
end

class Triangle < Polygon
  @sides = 3
end

class Rectangle < Polygon
  @sides = 4
end

class Square < Rectangle
end

class Hexagon < Polygon
  @sides = 6
end

puts "Triangle.sides:  #{Triangle.sides.inspect}"  # 3
puts "Rectangle.sides: #{Rectangle.sides.inspect}" # 4
puts "Square.sides:    #{Square.sides.inspect}"    # nil
puts "Hexagon.sides:   #{Hexagon.sides.inspect}"   # 6

मैंने Squareउदाहरण दिया (जो आउटपुट करता है nil) यह प्रदर्शित करने के लिए कि यह आपकी अपेक्षा के अनुरूप 100% व्यवहार नहीं कर सकता है; लेख मैं ऊपर लिंक विषय पर अतिरिक्त जानकारी के बहुत सारे है।

यह भी ध्यान रखें कि, अधिकांश डेटा के साथ, आपको एक मल्टीथ्रेड वातावरण में क्लास वेरिएबल्स के साथ बेहद सावधानी बरतनी चाहिए , जैसा कि डिमार्कोज़ की टिप्पणी के अनुसार।


1
यह उत्तर सही IMHO होगा यदि आपने कोड दिखाया जिसमें दिखाया गया है कि आप उप-वर्ग के बीच डेटा साझा करने के 'अजीब' व्यवहार के बिना वर्ग स्तर के डेटा को ट्रैक करने के लिए वर्ग स्तर पर एक इंस्टेंस चर का उपयोग कैसे कर सकते हैं।
फ्रॉग्ज

3
मैं यह भी कहना चाहता हूं कि बहु-थ्रेडेड वातावरण (जैसे रेल) ​​में कक्षा चर खतरनाक / अविश्वसनीय हो सकते हैं
डायलन मार्को

हम्म ... एक तरह से यह PHP में स्थिर चर की तरह लगता है, लेकिन विरासत का हिस्सा अलग है। मुझे नहीं लगता कि PHP में ऐसा कुछ है।
एंड्रयू

5
मुझे समझ नहीं आता कि ruby class << self endब्लॉक क्या करता है, विशेष रूप से << ऑपरेटर।
दविदुत्सु

1
दूसरों कि भ्रमित कर रहे हैं के लिए के बारे में class << selfदेखते हैं इस
kapad

37

@- एक वर्ग का उदाहरण चर
@@- वर्ग चर, जिसे कुछ मामलों में स्थिर चर भी कहा जाता है

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

वर्ग चर के सोचने का एक और तरीका एक वर्ग के संदर्भ में वैश्विक चर के रूप में है। वर्ग चर दो @अक्षरों ( @@) के साथ चर नाम को उपसर्ग द्वारा घोषित किया जाता है । सृजन के समय कक्षा के चर को आरंभ किया जाना चाहिए


10

@@ एक वर्ग चर को दर्शाता है, अर्थात इसे विरासत में मिला जा सकता है।

इसका मतलब यह है कि यदि आप उस वर्ग का उपवर्ग बनाते हैं, तो वह परिवर्तनशील होगा। इसलिए यदि आपके पास Vehicleवर्ग चर के साथ एक वर्ग है तो यदि आप एक वर्ग @@number_of_wheelsबनाते हैं class Car < Vehicleतो इसका भी वर्ग चर होगा@@number_of_wheels


इसका मतलब यह है कि यदि आप उस वर्ग का उपवर्ग बनाते हैं, तो वह परिवर्तनशील होगा। इसलिए यदि आपके पास Vehicleवर्ग चर के साथ एक वर्ग है तो यदि आप एक वर्ग @@number_of_wheelsबनाते हैं class Car < Vehicleतो इसका वर्ग चर भी होगा@@number_of_wheels
फारेश विजयरांगम

12
अगर मेरे पास एक class Vehicleहै @number_of_wheels, तो class Car < Vehicleएक उदाहरण चर भी होगा जिसे कहा जाता है @number_of_wheels। वर्ग चर के साथ महत्वपूर्ण अंतर यह है कि वर्गों में एक ही चर होता है, जैसे कि एक को बदलने से दूसरे में परिवर्तन होता है।
मिशेल टिली

1

जब मॉड्यूल किसी वर्ग का विस्तार करता है या उस मॉड्यूल को शामिल करता है, तो @ और @@ भी अलग तरीके से काम करते हैं।

तो दिया

module A
    @a = 'module'
    @@a = 'module'

    def get1
        @a          
    end     

    def get2
        @@a         
    end     

    def set1(a) 
        @a = a      
    end     

    def set2(a) 
        @@a = a     
    end     

    def self.set1(a)
        @a = a      
    end     

    def self.set2(a)
        @@a = a     
    end     
end 

फिर आप नीचे दिए गए आउटपुट को टिप्पणियों के रूप में दिखाए

class X
    extend A

    puts get1.inspect # nil
    puts get2.inspect # "module"

    @a = 'class' 
    @@a = 'class' 

    puts get1.inspect # "class"
    puts get2.inspect # "module"

    set1('set')
    set2('set')

    puts get1.inspect # "set" 
    puts get2.inspect # "set" 

    A.set1('sset')
    A.set2('sset')

    puts get1.inspect # "set" 
    puts get2.inspect # "sset"
end 

class Y
    include A

    def doit
        puts get1.inspect # nil
        puts get2.inspect # "module"

        @a = 'class'
        @@a = 'class'

        puts get1.inspect # "class"
        puts get2.inspect # "class"

        set1('set')
        set2('set')

        puts get1.inspect # "set"
        puts get2.inspect # "set"

        A.set1('sset')
        A.set2('sset')

        puts get1.inspect # "set"
        puts get2.inspect # "sset"
    end
end

Y.new.doit

इसलिए @@ का उपयोग उन चर के लिए करें जो आप उनके सभी उपयोगों के लिए सामान्य चाहते हैं, और उन चर के मॉड्यूल में @ का उपयोग करें जिन्हें आप हर उपयोग के संदर्भ के लिए अलग चाहते हैं।


1

उत्तर आंशिक रूप से सही हैं क्योंकि @@ वास्तव में एक वर्ग चर है जो प्रति वर्ग पदानुक्रम है जिसका अर्थ है कि यह एक वर्ग, उसके उदाहरणों और उसके वंशजों और उनके उदाहरणों द्वारा साझा किया जाता है।

class Person
  @@people = []

  def initialize
    @@people << self
  end

  def self.people
    @@people
  end
end

class Student < Person
end

class Graduate < Student
end

Person.new
Student.new

puts Graduate.people

यह आउटपुट करेगा

#<Person:0x007fa70fa24870>
#<Student:0x007fa70fa24848>

इसलिए व्यक्ति, छात्र और स्नातक कक्षाओं के लिए केवल एक ही @ चर है और इन वर्गों के सभी वर्ग और उदाहरण विधियाँ एक ही चर को संदर्भित करती हैं।

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

class Person

  def initialize
    self.class.add_person self
  end

  def self.people
    @people
  end

  def self.add_person instance
    @people ||= []
    @people << instance
  end
end

class Student < Person
end

class Graduate < Student
end

Person.new
Person.new
Student.new
Student.new
Graduate.new
Graduate.new

puts Student.people.join(",")
puts Person.people.join(",")
puts Graduate.people.join(",")

यहाँ, @ लोग वर्ग पदानुक्रम के बजाय प्रति वर्ग एकल हैं क्योंकि यह वास्तव में प्रत्येक वर्ग उदाहरण पर संग्रहीत एक चर है। यह आउटपुट है:

#<Student:0x007f8e9d2267e8>,#<Student:0x007f8e9d21ff38>
#<Person:0x007f8e9d226158>,#<Person:0x007f8e9d226608>
#<Graduate:0x007f8e9d21fec0>,#<Graduate:0x007f8e9d21fdf8> 

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

इसलिए जब अन्य उत्तर सही ढंग से बताते हैं कि @myvariable (सिंगल @ नोटेशन के साथ) हमेशा एक उदाहरण चर है, तो इसका मतलब यह नहीं है कि यह उस वर्ग के सभी उदाहरणों के लिए एक साझा साझा चर नहीं है।

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