2009-12-06 20 views
11

मैं मनोरंजन प्रयोजनों के लिए रूबी और ओपनगल के साथ गड़बड़ कर रहा हूं, और मैंने कुछ गणित को सुंदर बनाने के लिए कुछ 3 डी वेक्टर/विमान/आदि कक्षाएं लिखने का फैसला किया।रूबी ऑपरेटर ओवरलोडिंग प्रश्न

सरलीकृत उदाहरण:

class Vec3 
    attr_accessor :x,:y,:z 

    def *(a) 
     if a.is_a?(Numeric) #multiply by scalar 
      return Vec3.new(@x*a, @y*a, @z*a) 
     elsif a.is_a?(Vec3) #dot product 
      return @x*a.x + @y*a.y + @z*a.z 
     end 
    end 
end 

v1 = Vec3.new(1,1,1) 
v2 = v1*5 #produces [5,5,5] 

जो सब ठीक और dandy, लेकिन मैं भी

v2 = 5*v1 

जो Fixnum में कार्यक्षमता जोड़ने की आवश्यकता है लिख सकते हैं या फ्लोट या जो कुछ भी करने में सक्षम होना चाहते हैं, लेकिन मैं नहीं कर सके इसे पूरी तरह से बदले बिना फिक्सम के गुणा को ओवरलोड या विस्तारित करने का कोई तरीका नहीं है। क्या यह रूबी में संभव है? कोई सुझाव?

(जाहिर है मैं सिर्फ सही क्रम में अपने सभी गुणा अगर मैं करने की जरूरत है लिख सकते हैं)

+0

के बराबर है ई रिकॉर्ड, '@ x * s, @ y * s, @ z * s' से '@ x * a, @ y * a, @ z * a' में बदलें, अन्यथा आपका कोड टूटा हुआ है। –

+0

धन्यवाद, एक ही समय में 2 स्थानों से कोड कॉपी किया गया है <<अब तय किया जाना चाहिए –

उत्तर

21

का उपयोग विवश बंदर-पैच एक कोर वर्ग की तुलना में काफी बेहतर तरीका है:

class Vec3 
    attr_accessor :x,:y,:z 

    def *(a) 
     if a.is_a?(Numeric) #multiply by scalar 
      return Vec3.new(@x*a, @y*a, @z*a) 
     elsif a.is_a?(Vec3) #dot product 
      return @x*a.x + @y*a.y + @z*a.z 
     end 
    end 

    def coerce(other) 
     return self, other 
    end 
end 

अगर आप v = Vec3.new के रूप में वी परिभाषित फिर निम्न काम करेगा: v * 5 और 5 * v पहला तत्व द्वारा लौटाए गए कॉरपोरेशन (स्वयं) ऑपरेशन के लिए नया रिसीवर बन जाता है, और दूसरा तत्व (अन्य) पैरामीटर बन जाता है, इसलिए 5 * v बिल्कुल v * 5

+1

+1। उस व्यक्ति की ओर से जिसने अपना कोड डीबग करना है, कृपया सुपर-डुप्कर-बिल्कुल जरूरी होने तक कोर क्लास को बंदरगाह न करें। – zenazn

+0

यह मेरी जरूरत के लिए बहुत अच्छा काम किया। अगर मैं एक समान उदाहरण में चलता हूं जो कम्यूटिव नहीं हो सकता है तो मुझे लगता है कि मैं आवश्यकतानुसार बंदर पैच रखूंगा;) –

+0

वाणिज्य को हमेशा दूसरे तर्क के रूप में 'स्वयं' वापस करना चाहिए! अन्यथा आप तर्कों की कम्यूटिटीविटी को गड़बड़ करते हैं। इसके बजाए, 'वाणिज्य' को उस प्रकार के तर्क को डालना चाहिए जिसे गुणा किया जा सकता है (उदाहरण के लिए: 'Vec3.new (अन्य, अन्य, अन्य) ')। जाहिर है यह इसकी अपनी समस्याओं के बिना नहीं है। –

-1

मेरा मानना ​​है कि निम्नलिखित तुम क्या चाहते हो जाएगा, हालांकि banister's suggestioncoerce के बजाय का उपयोग करने के बंदर-पैच Numeric एक पसंदीदा है तरीका। यदि आवश्यक हो तो इस विधि का उपयोग करें (उदाहरण के लिए यदि आप केवल कुछ बाइनरी ऑपरेंड को संक्रमणीय होना चाहते हैं)।

Fixnum.class_eval do 
    original_times = instance_method(:*) 
    define_method(:*) do |other| 
    if other.kind_of?(Vec3) 
     return other * self 
    else 
     return original_times.bind(self).call(other) 
    end 
    end 
end 
+1

मिमीएम सेक्सी :) बीटीडब्ल्यू, मुझे पहली पंक्ति को "Fixnum.class_eval do" या (समकक्ष?) "वर्ग फिक्सम" –

+1

में बदलने की आवश्यकता है क्लास_वेल के बिना इसे फिक्सनम क्लास पर सीधे परिभाषित करना संभव नहीं है, और define_method की बजाय नियमित डीफ़ करना है? – horseyguy

+0

ठीक है, यह कोड पागल है :) न केवल आपको कक्षा_ईवल की आवश्यकता नहीं है (एक सामान्य वर्ग निकाय ठीक करेगा) आप अबाउट विधि ऑब्जेक्ट्स के साथ हास्यास्पद चीजें कर रहे हैं जो पूरी तरह से अनावश्यक हैं। क्यों न केवल alias_method का उपयोग करें? ;) उल्लेख नहीं है कि एक कोर क्लास बंदर-पैचिंग बहुत बड़ा नहीं है :) – horseyguy

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