रूबी: उदाहरण के लिए कक्षा विधि को कॉल करना


347

रूबी में, आप उस वर्ग के उदाहरणों में से एक वर्ग विधि को कैसे कहते हैं? कहो मेरे पास है

class Truck
  def self.default_make
    # Class method.
    "mac"
  end

  def initialize
    # Instance method.
    Truck.default_make  # gets the default via the class's method.
    # But: I wish to avoid mentioning Truck. Seems I'm repeating myself.
  end
end

लाइन Truck.default_makeडिफ़ॉल्ट को पुनः प्राप्त करती है। लेकिन क्या बिना उल्लेख के यह कहने का एक तरीका है Truck? ऐसा लगता है कि वहाँ होना चाहिए।

जवाबों:


563

वर्ग के शाब्दिक नाम का उल्लेख करने के बजाय, एक उदाहरण विधि के अंदर आप बस कॉल कर सकते हैं self.class.whatever

class Foo
    def self.some_class_method
        puts self
    end

    def some_instance_method
        self.class.some_class_method
    end
end

print "Class method: "
Foo.some_class_method

print "Instance method: "
Foo.new.some_instance_method

आउटपुट:

कक्षा विधि: फू
उदाहरण विधि: फू

7
मैं एक उदाहरण से एक वर्ग विधि को कॉल करने के लिए रूबी में कुछ शॉर्टकट देखना चाहूंगा। यानी: some_class_method बजाय self.class.some_class_method
phoet

7
हालांकि यह सही उत्तर है, यह शर्म की बात है कि "self.class" वर्ग नाम "ट्रक" की तुलना में अधिक टाइपिंग और पढ़ने में कम आसान है। ओह अच्छा ....
मैट कॉनॉली

22
@MattConnolly, यह रिश्तेदार है, अगर आपकी कक्षा का नाम है SalesforceSyncJobतो यह छोटा है;)
2:00

29
@MattConnolly, self.classवर्ग का नाम बदलने के लिए होने पर खोज / प्रतिस्थापन की आवश्यकता को समाप्त करती है।
गस शॉर्टज

8
@GusShortz सच। इसके अलावा, अगर एक उपवर्ग हो तो self.class बेहतर काम करता है।
मैट कोनोली

183

का उपयोग self.class.blahका उपयोग कर के रूप में ही नहीं है ClassName.blah, जब यह विरासत की बात आती है।

class Truck
  def self.default_make
    "mac"
  end

  def make1
    self.class.default_make
  end

  def make2
    Truck.default_make
  end
end


class BigTruck < Truck
  def self.default_make
    "bigmac"
  end
end

ruby-1.9.3-p0 :021 > b=BigTruck.new
 => #<BigTruck:0x0000000307f348> 
ruby-1.9.3-p0 :022 > b.make1
 => "bigmac" 
ruby-1.9.3-p0 :023 > b.make2
 => "mac" 

58
यह प्रश्न के उत्तर के बजाय स्वीकृत उत्तर की प्रतिक्रिया प्रतीत होती है।
जिऑन

16
@ ज़ोन - सच है, लेकिन यह अभी भी उपयोगी संदर्भ है जब विचार करना है कि क्या उपयोग करना है।
मैट सैंडर्स

1
@MattSanders सिर्फ उन मामलों में एक टिप्पणी का उपयोग करते हैं।
nandilugio

1
self.classविरासत के संरक्षण के लिए @ हॉल सही है। भले ही make1()इसे परिभाषित किया गया हो Truck, यह संदर्भित करने BigTruckका वर्ग तरीका है।
कैसर शाहिद

14

उदाहरण विधि के अंदर एक वर्ग विधि का उपयोग करने के लिए, निम्न कार्य करें:

self.class.default_make

यहाँ आपकी समस्या के लिए एक वैकल्पिक समाधान है:

class Truck

  attr_accessor :make, :year

  def self.default_make
    "Toyota"
  end

  def make
    @make || self.class.default_make
  end

  def initialize(make=nil, year=nil)
    self.year, self.make = year, make
  end
end

अब हमारी कक्षा का उपयोग करते हैं:

t = Truck.new("Honda", 2000)
t.make
# => "Honda"
t.year
# => "2000"

t = Truck.new
t.make
# => "Toyota"
t.year
# => nil

मेक एक इंस्टेंस मेथड नहीं होना चाहिए। इसे और अधिक कारखाने का एक प्रकार है कि बजाय एक उदाहरण वर्ग के लिए बाध्य किया जाना चाहिए है
phoet

6
@phoet मेक शब्द एक कार (टोयोटा, बीएमडब्ल्यू आदि के रूप में) को दर्शाता है । नामकरण उपयोगकर्ता की आवश्यकता पर आधारित है
हरीश शेट्टी

8

यदि आपके पास प्रतिनिधि विधि तक पहुंच है, तो आप ऐसा कर सकते हैं:

[20] pry(main)> class Foo
[20] pry(main)*   def self.bar
[20] pry(main)*     "foo bar"
[20] pry(main)*   end  
[20] pry(main)*   delegate :bar, to: 'self.class'
[20] pry(main)* end  
=> [:bar]
[21] pry(main)> Foo.new.bar
=> "foo bar"
[22] pry(main)> Foo.bar
=> "foo bar"

वैकल्पिक रूप से, और शायद क्लीनर अगर आपके पास अधिक है तो एक विधि या दो जिसे आप वर्ग और उदाहरण के लिए सौंपना चाहते हैं:

[1] pry(main)> class Foo
[1] pry(main)*   module AvailableToClassAndInstance
[1] pry(main)*     def bar
[1] pry(main)*       "foo bar"
[1] pry(main)*     end  
[1] pry(main)*   end  
[1] pry(main)*   include AvailableToClassAndInstance
[1] pry(main)*   extend AvailableToClassAndInstance
[1] pry(main)* end  
=> Foo
[2] pry(main)> Foo.new.bar
=> "foo bar"
[3] pry(main)> Foo.bar
=> "foo bar"

चेतावनी:

बस बेतरतीब ढंग से delegateसब कुछ न करें जो राज्य को वर्ग और उदाहरण में नहीं बदलता है क्योंकि आप अजीब नाम के टकराव के मुद्दों में भागना शुरू कर देंगे। इसे संयम से करें और आपके द्वारा जाँच के बाद ही कुछ और न लिखा जाए।



5

आप इसे सही तरीके से कर रहे हैं। क्लास मेथड (C ++ या Java में 'स्टैटिक' विधियों के समान) उदाहरण का हिस्सा नहीं हैं, इसलिए उन्हें सीधे संदर्भित करना होगा।

उस नोट पर, आपके उदाहरण में आप 'default_make' को एक नियमित विधि बनाने में बेहतर साबित होंगे:

#!/usr/bin/ruby

class Truck
    def default_make
        # Class method.
        "mac"
    end

    def initialize
        # Instance method.
        puts default_make  # gets the default via the class's method.
    end
end

myTruck = Truck.new()

कक्षा के तरीके उपयोगिता-प्रकार के कार्यों के लिए अधिक उपयोगी होते हैं जो कक्षा का उपयोग करते हैं। उदाहरण के लिए:

#!/usr/bin/ruby

class Truck
    attr_accessor :make

    def default_make
        # Class method.
        "mac"
    end

    def self.buildTrucks(make, count)
        truckArray = []

        (1..count).each do
            truckArray << Truck.new(make)
        end

        return truckArray
    end

    def initialize(make = nil)
        if( make == nil )
            @make = default_make()
        else
            @make = make
        end
    end
end

myTrucks = Truck.buildTrucks("Yotota", 4)

myTrucks.each do |truck|
    puts truck.make
end

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

1
@Peter क्या आप इसे सरल शब्दों में समझाना चाहेंगे? मैं सिर्फ रूबी को सीख रहा हूं और महा के जवाब मुझे सही लगते हैं।
मारलेन टीबी

1
@ MarlenT.B। पीछे मुड़कर देखना मुझे यकीन नहीं है कि यहां बहुत कुछ सीखा जा सकता है - मैं केवल इस बात पर बहस कर रहा था कि विधि को रखने के लिए सबसे अच्छी जगह कहां है, और मैं अपने तर्क को दृढ़ता से नहीं खरीदता हूं! :)
पीटर

2
मैं भी असहमत हूं। चाहे कुछ एक वर्ग विधि हो "उपयोगिता" से कोई लेना देना नहीं है। यह इस बारे में है कि क्या विधि वैचारिक रूप से कक्षा के लिए लागू होती है, या उस वर्ग की कोई वस्तु। उदाहरण के लिए, हर ट्रक का एक अलग सीरियल नंबर होता है, इसलिए serial_number एक इंस्टेंस विधि है (संबंधित उदाहरण चर के साथ)। अन्य वाहन_टाइप पर (जो "ट्रक" लौटाता है) एक वर्ग विधि होनी चाहिए क्योंकि यह सभी ट्रकों की संपत्ति है, विशेष ट्रक नहीं
vish

3

एक और:

class Truck
  def self.default_make
    "mac"
  end

  attr_reader :make

  private define_method :default_make, &method(:default_make)

  def initialize(make = default_make)
    @make = make
  end
end

puts Truck.new.make # => mac

1

यहां बताया गया है कि आप इस स्थिति के लिए _classकाम करने वाले तरीके को कैसे लागू कर सकते हैं self.class। नोट: इसे उत्पादन कोड में उपयोग न करें, यह ब्याज के लिए है :)

से: क्या आप रूबी में कॉल करने वाले के संदर्भ में कोड निकाल सकते हैं? और http://rubychallenger.blogspot.com.au/2011/07/caller-binding.html भी

# Rabid monkey-patch for Object
require 'continuation' if RUBY_VERSION >= '1.9.0'
class Object
  def __; eval 'self.class', caller_binding; end
  alias :_class :__
  def caller_binding
    cc = nil; count = 0
    set_trace_func lambda { |event, file, lineno, id, binding, klass|
      if count == 2
        set_trace_func nil
        cc.call binding
      elsif event == "return"
        count += 1
      end
    }
    return callcc { |cont| cc = cont }
  end
end

# Now we have awesome
def Tiger
  def roar
    # self.class.roar
    __.roar
    # or, even
    _class.roar
  end
  def self.roar
    # TODO: tigerness
  end
end

शायद सही जवाब रूबी के लिए एक पैच जमा करना है :)


-6

अपने प्रश्न के समान, आप उपयोग कर सकते हैं:

class Truck
  def default_make
    # Do something
  end

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