2010-02-27 12 views
17

आरंभ निम्नलिखित वर्ग को देखते हुए संपत्ति मूल्यों की स्थापना nil अभी भी। क्या यह संभव है?रूबी जब वस्तु

नोट: मैं प्रारंभकर्ता नहीं जोड़ना चाहता हूं।

+0

प्रारंभिक विधि को हल करना (क्या आपका मतलब है?) चीजों को मुश्किल बनाता है। नई 'टेस्ट' ऑब्जेक्ट्स बनाते समय, 'नाम' को प्रत्येक बार समान प्रारंभिकता प्राप्त करनी चाहिए? या इसे ओपन कोड में निर्दिष्ट मान प्राप्त करना चाहिए? – DigitalRoss

+2

प्रेरणा सी # के समान कुछ करना होगा - http://msdn.microsoft.com/en-us/library/bb384062.aspx –

+0

क्या ऐसा कुछ है जिसे आप प्रस्तावित समाधान के साथ पसंद नहीं करते हैं? –

उत्तर

0

जो कोड आप इंगित कर रहे हैं वह initialize फ़ंक्शन में पैरामीटर पास कर रहा है।

test = Test.new 
test.name = 'Some test object' 
9

दूसरों के द्वारा उल्लेख किया है, यह करने के लिए सबसे आसान तरीका है किया जाएगा एक initialize विधि को परिभाषित करने के: आप सबसे निश्चित रूप से या तो initialize उपयोग करें, या एक और अधिक उबाऊ सिंटैक्स का उपयोग करना होगा। यदि आप ऐसा नहीं करना चाहते हैं, तो आप अपनी कक्षा Struct से प्राप्त कर सकते हैं।

class Test < Struct.new(:name) 
end 

तो अब:

>> t = Test.new("Some Test Object") 
=> #<struct Test name="Some Test Object"> 
>> t.name 
=> "Some Test Object" 
18

ठीक है,

मैं एक समाधान के साथ आया था। यह प्रारंभिक विधि का उपयोग करता है लेकिन दूसरी ओर वही करें जो आप चाहते हैं।

class Test 
    attr_accessor :name 

    def initialize(init) 
    init.each_pair do |key, val| 
     instance_variable_set('@' + key.to_s, val) 
    end 
    end 

    def display 
    puts @name 
    end 

end 

t = Test.new :name => 'hello' 
t.display 

खुश? :)


विरासत का उपयोग कर वैकल्पिक समाधान। नोट, इस समाधान के साथ, आपको स्पष्ट रूप से attr_accessor घोषित करने की आवश्यकता नहीं है!

class CSharpStyle 
    def initialize(init) 
    init.each_pair do |key, val| 
     instance_variable_set('@' + key.to_s, val) 
     instance_eval "class << self; attr_accessor :#{key.to_s}; end" 
    end 
    end 
end 

class Test < CSharpStyle 
    def initialize(arg1, arg2, *init) 
    super(init.last) 
    end 
end 

t = Test.new 'a val 1', 'a val 2', {:left => 'gauche', :right => 'droite'} 
puts "#{t.left} <=> #{t.right}" 
7

आवश्यक क्रियाओं के साथ जटिल ऑब्जेक्ट प्रारंभिक-पासिंग ब्लॉक करने का एक सामान्य तरीका है। यह ब्लॉक वस्तु के संदर्भ में मूल्यांकन किया जा सकता है, ताकि आप सभी उदाहरण चर के लिए आसान पहुँच है, तरीकों आदि

अपने उदाहरण को जारी

class Test 
    attr_accessor :name 

    def initialize(&block) 
    instance_eval(&block) 
    end 
end 

और फिर

t = Test.new { @name = 'name' } 

या

t = Test.new do 
    self.name = 'name' 
    # other initialization, if needed 
end 

ध्यान दें कि इस तरह सेकी जटिल परिवर्तन की आवश्यकता नहीं हैविधि (जो वास्तव में, एक-लाइनर है)।

0

टेस्ट उपवर्ग की जरूरत है सकते हैं (यहाँ खुद विधि और प्रारंभकर्ता साथ दिखाया गया है) उदा .:

class Test 
    attr_accessor :name, :some_var 

    def initialize some_var 
    @some_var = some_var 
    end 

    def some_function 
    "#{some_var} calculation by #{name}" 
    end 
end 

class SubClassedTest < Test 
    def initialize some_var, attrbs 
    attrbs.each_pair do |k,v| 
     instance_variable_set('@' + k.to_s, v) 
    end 
    super(some_var) 
    end 
end 

tester = SubClassedTest.new "some", name: "james" 
puts tester.some_function 

आउटपुट: some calculation by james

0

आप ऐसा कर सकता है।

class Test 
    def not_called_initialize(but_act_like_one) 
     but_act_like_one.each_pair do |variable,value| 
      instance_variable_set('@' + variable.to_s, value) 
      class << self 
        self 
      end.class_eval do 
        attr_accessor variable 
      end 
     end 
    end 
end 

(t = Test.new).not_called_initialize :name => "Ashish", :age => 33 
puts t.name #=> Ashish 
puts t.age #=> 33 

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

0

यदि आप initialize को ओवरराइड नहीं करना चाहते हैं तो आपको श्रृंखला को ऊपर ले जाना होगा और new ओवरराइड करना होगा। यहाँ एक उदाहरण है:

class Foo 
    attr_accessor :bar, :baz 

    def self.new(*args, &block) 
    allocate.tap do |instance| 
     if args.last.is_a?(Hash) 
     args.last.each_pair do |k,v| 
      instance.send "#{k}=", v 
     end 
     else 
     instance.send :initialize, *args 
     end 
    end 
    end 

    def initialize(*args) 
    puts "initialize called with #{args}" 
    end 
end 

आखिरी बात आप में पारित एक हैश यह initialize बाईपास और setters तुरंत फोन जाएगा। यदि आप इसमें कुछ और पास करते हैं तो उन तर्कों के साथ आरंभ करने के लिए कॉल करेंगे।

1

जैसा कि पहले उल्लेख किया गया था, ऐसा करने का समझदार तरीका या तो Struct या Test#initialize विधि को परिभाषित करके है। यह वही है जो structs और रचनाकारों के लिए हैं। गुण के लिए इसी एक विकल्प हैश का उपयोग कर अपने सी # उदाहरण के निकटतम बराबर है, और यह एक सामान्य दिखने रूबी सम्मेलन है:

t = Test.new({:name => "something"}) 
t = Test.new(name: "something") # json-style or kwargs 

लेकिन अपने उदाहरण में आप कुछ है कि अधिक चर काम की तरह लग रहा = का उपयोग कर तो चलो चलो कर रहे हैं हैश के बजाय ब्लॉक का उपयोग करने का प्रयास करें। (आप भी Name उपयोग कर रहे हैं जो रूबी में एक निरंतर हो सकता है, हम चाहते हैं कि बदल देंगे।)

t = Test.new { @name = "something" } 

कूल, अब की कि वास्तव में काम करते हैं:

class BlockInit 
    def self.new(&block) 
    super.tap { |obj| obj.instance_eval &block } 
    end 
end 

class Test < BlockInit 
    attr_accessor :name 
end 

t = Test.new { @name = "something" } 
# => #<Test:0x007f90d38bacc0 @name="something"> 
t.name 
# => "something" 

हम एक बना लिया है एक निर्माता के साथ वर्ग जो ब्लॉक तर्क स्वीकार करता है, जिसे नव-तत्काल वस्तु के भीतर निष्पादित किया जाता है।

क्योंकि आप ने कहा आप initialize का उपयोग कर से बचना चाहते थे, मैं बजाय अधिभावी new और super बुला Object#new से डिफ़ॉल्ट व्यवहार प्राप्त करने के लिए कर रहा हूँ। आम तौर पर हम initialize को को परिभाषित करेंगे, इस प्रश्न को आपके प्रश्न में विशिष्ट अनुरोध को पूरा करने के अलावा अनुशंसित नहीं है।

जब हम BlockInit के उप-वर्ग में ब्लॉक पास करते हैं तो हम केवल चर सेट करने से अधिक कर सकते हैं ... हम अनिवार्य रूप से initialize विधि (जिसे हम लेखन से परहेज कर रहे हैं) में कोड इंजेक्ट कर रहे हैं। तुम भी है कि अन्य सामान करता है एक initialize तरीका चाहते थे तो (के रूप में आप टिप्पणी में उल्लेख किया है) आप Test करने के लिए इसे जोड़ सकते हैं और नहीं भी super

आशा है कि कॉल करने के लिए (के बाद से हमारे परिवर्तन BlockInit#initialize में नहीं बल्कि BlockInit.new नहीं हैं,) है एक बहुत ही विशिष्ट और मनोरंजक अनुरोध के लिए एक रचनात्मक समाधान।

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