2017-12-14 1 views
5

इस स्क्रिप्टविधि नामित `मुख्य मॉड्यूल में hash` किसी वस्तु के` hash` विधि

def hash 
    puts "why?" 
end 

x = {} 
x[[1,2]] = 42 

यह आउटपुट

why? 
/tmp/a.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError) 
    from /tmp/a.rb:6:in `<main>' 

निम्नलिखित ऐसा लगता है hash समारोह लिपि में defned है कि यह देखते हुए ओवरराइड करता है उस मामले में Array#hash ओवरराइडिंग। चूंकि मेरे hash विधि का वापसी मूल्य nil है और Integer नहीं है, यह अपवाद फेंकता है। निम्न स्क्रिप्ट इस

puts [1,2,3].hash 

def hash 
    puts "why?" 
end 

puts [1,2,3].hash 

उत्पादन

-4165381473644269435 
why? 
/tmp/b.rb:6:in `hash': no implicit conversion of nil into Integer (TypeError) 
    from /tmp/b.rb:6:in `<main>' 

मैं रूबी स्रोत कोड में देख कोशिश की लेकिन समझ नहीं सकता है कि ऐसा क्यों होता है पुष्टि करने के लिए लगता है। क्या यह व्यवहार दस्तावेज है?

+0

मुझे यह व्यवहार नहीं मिल रहा है। 'कक्षा ऐरे; डीफ़ हैश; शून्य; समाप्त; समाप्त; रखता है [1,2,3] .शैश एक खाली रेखा प्रिंट करता है और मेरे लिए शून्य देता है। 'एक्स [[1,2]] = 1' अभी भी टाइप एरर उठाता है, लेकिन 'x [nil] = 1' ठीक काम करता है। वास्तव में विचित्र व्यवहार .. आप किस रूबी संस्करण पर हैं? मैं 2.3.1 –

उत्तर

4

आप अधिभावी नहीं कर रहे हैं Array#hash, आप Object#hash बनाकर Kernel#hash पीछा कर रहे हैं:

puts method(:hash) 
def hash 
    puts "why?" 
end 
puts method(:hash) 

प्रिंट यही कारण है कि:

#<Method: Object(Kernel)#hash> 
#<Method: Object#hash> 

इसे ठीक करें ताकि हम और अधिक देख सकते हैं :

def hash 
    puts "why?" 
    super 
end 

x = {} 
x[[1,2]] = 42 

अब उत्पादन होता है:

why? 
why? 

और कोई त्रुटि। इसे x[[1,2,3,4,5,6,7]] = 42 के साथ आज़माएं और इसके बजाय आप why? मुद्रित सात बार देखेंगे। एक बार प्रत्येक सरणी तत्व के लिए, क्योंकि सरणी की हैश विधि इसके तत्वों के हैंश का उपयोग करती है।और Integer#hash मौजूद नहीं है, यह hash विधि Object/Kernel से प्राप्त करता है, इसलिए आपका उपयोग किया जाता है।

+1

मेरे सिस्टम पर दूसरी 'विधि (हैश) वास्तव में दुभाषिया को दुर्घटनाग्रस्त करता है। हो सकता है कि रूबी देवों को चेतावनी दी जानी चाहिए जब शीर्ष-स्तर हैश परिभाषित किया गया है ... – Max

+0

आपने इसे कहां/कैसे किया? आईआरबी में या तो, या आपने इसे एक स्क्रिप्ट फ़ाइल में सहेजा और इसे चलाया? –

+0

केवल आईआरबी में यह दुर्घटनाग्रस्त हो जाता है। लेकिन 'ऑब्जेक्ट # हैश' को फिर से परिभाषित करना अभी भी चेतावनी योग्य चीज़ की तरह दिखता है। मैं नहीं देख सकता कि कभी भी एक अच्छा विचार है। – Max

3

यह रूबी शीर्ष स्तर में एक तरह का हैक के कारण है। क्या आपने कभी सोचा है कि यह कैसे काम करता है?

def foo 
end 
p self 
foo 

class Bar 
    def test 
    p self 
    foo 
    end 
end 

Bar.new.test # no error 

कैसे दो पूरी तरह से अलग वस्तुओं (main और एक Bar) foo कॉल करने के लिए यह एक निजी विधि कॉल है जैसे में सक्षम हैं? इसका कारण यह है कि ... यह एक निजी विधि कॉल है।

जब आप अपनी रूबी स्क्रिप्ट के शीर्ष स्तर पर कोई विधि परिभाषित करते हैं, तो यह प्रत्येक ऑब्जेक्ट में (Object के माध्यम से) शामिल हो जाता है। यही कारण है कि आप शीर्ष-स्तरीय विधियों को कॉल कर सकते हैं जैसे कि वे वैश्विक कार्य हैं।

लेकिन यह केवल hash क्यों टूटता है और अन्य सामान्य तरीकों से क्यों नहीं? उदाहरण के लिए def to_s;endto_s तोड़ नहीं देगा। इसका कारण यह है कि hash रिकर्सिव है: अधिकांश * कक्षा कार्यान्वयन अंततः Object#hash पर उनके कार्यान्वयन के लिए कॉल करते हैं। उस बेस केस को फिर से परिभाषित करके, आप इसे वैश्विक रूप से तोड़ते हैं। to_s जैसी अन्य विधियों के लिए आपको वैश्विक परिवर्तन नहीं दिखाई देगा क्योंकि यह विरासत श्रृंखला का तरीका है और इसे शामिल नहीं किया जाता है।

* केवल एक ही वस्तु जो टूटती नहीं है वह कुछ अक्षर हैं जिनके पास शायद हार्ड-कोड वाले हैश मान हैं। []{}""true आदि

+1

हम्म का उपयोग कर रहा हूं, 'x [[[], {}, ""]] = 42' और 'x [true] = 42' कोई त्रुटि नहीं देता है, लेकिन' x [[true] ] = 42' करता है। मैं अभी तक यह समझा नहीं सकता ... –

+0

@StefanPochmann जो सुपर अजीब – Max

+0

है, मुझे अपराधी मिल सकता है। [लाइन 666] पर शुरू होता है (https://github.com/ruby/ruby/blob/9cbb3bd1f2b05d59b6dd315ebdec295c2ced6c01/hash.c#L666) :-)। ऐसा लगता है कि 'सत्य' के हैश मान प्राप्त करने के लिए 'x [true]' 'RHASH' का उपयोग करता है। जिसे परिभाषित किया गया है ['internal.h' में] (https://github.com/ruby/ruby/blob/9cbb3bd1f2b05d59b6dd315ebdec295c2ced6c01/internal.h#L669), तो मुझे लगता है कि वास्तव में हमारे' हैश विधि। लेकिन 'ऐरे # हैश' ['rb_hash'] का उपयोग करता है (https://github.com/ruby/ruby/blob/trunk/array.c#L3964), जो स्पष्ट रूप से हमारे उच्च स्तरीय' हैश' विधि का उपयोग करता है। –

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