मुझे यह कोड RailsCast में मिला :
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
क्या करता है (&:name)
में map(&:name)
मतलब?
मुझे यह कोड RailsCast में मिला :
def tag_names
@tag_names || tags.map(&:name).join(' ')
end
क्या करता है (&:name)
में map(&:name)
मतलब?
जवाबों:
इसके लिए आशुलिपि है tags.map(&:name.to_proc).join(' ')
यदि foo
एक to_proc
विधि के साथ एक वस्तु है , तो आप इसे एक विधि के रूप में पास कर सकते हैं &foo
, जो foo.to_proc
उस विधि के ब्लॉक के रूप में कॉल और उपयोग करेगा ।
Symbol#to_proc
विधि मूल रूप से ActiveSupport से जोड़ा गया है लेकिन रूबी 1.8.7 में एकीकृत किया गया। यह इसका कार्यान्वयन है:
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
&
, अर्थातtags.map(&:name.to_proc).join(' ')
एक और शांत आशुलिपि, कई के लिए अज्ञात है
array.each(&method(:foo))
जो एक आशुलिपि है
array.each { |element| foo(element) }
कॉल करके method(:foo)
हमने उससे एक Method
वस्तु ली self
जो उसकी foo
विधि का प्रतिनिधित्व करता है, और &
यह दर्शाता है कि यह एक to_proc
विधि है जो इसे एक में परिवर्तित करती है Proc
।
यह बहुत उपयोगी है जब आप चीजों को बिंदु-मुक्त शैली करना चाहते हैं। एक उदाहरण यह देखना है कि क्या स्ट्रिंग में कोई स्ट्रिंग है जो स्ट्रिंग के बराबर है "foo"
। पारंपरिक तरीका है:
["bar", "baz", "foo"].any? { |str| str == "foo" }
और बिंदु मुक्त तरीका है:
["bar", "baz", "foo"].any?(&"foo".method(:==))
पसंदीदा तरीका सबसे अधिक पठनीय होना चाहिए।
array.each{|e| foo(e)}
अभी भी छोटा है :-) +1 कहीं भी
&method
?
[1,2,3].map(&Array.method(:new))
इसके बराबर है
def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end
जबकि हम यह भी ध्यान दें कि एम्परसेंड #to_proc
जादू किसी भी वर्ग के साथ काम कर सकता है, केवल प्रतीक नहीं। कई रुबाइयाँ #to_proc
ऐरे वर्ग पर परिभाषित करने के लिए चुनते हैं :
class Array
def to_proc
proc { |receiver| receiver.send *self }
end
end
# And then...
[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]
Ampersand अपने ऑपरेंड पर संदेश &
भेजकर काम करता है to_proc
, जो उपरोक्त कोड में, ऐरे वर्ग का है। और जब से मैंने #to_proc
ऐरे पर विधि को परिभाषित किया , रेखा बन गई:
[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
इसके लिए आशुलिपि है tags.map { |tag| tag.name }.join(' ')
&
ऑपरेटर to_proc
अपने ऑपरेंड पर कॉल करता है। तो यह मानचित्र विधि के लिए विशिष्ट नहीं है, और वास्तव में किसी भी विधि पर काम करता है जो ब्लॉक लेता है और ब्लॉक को एक या अधिक तर्क देता है।
जोश ली का उत्तर लगभग सही है सिवाय इसके कि रूबी कोड निम्नानुसार होना चाहिए था।
class Symbol
def to_proc
Proc.new do |receiver|
receiver.send self
end
end
end
नहीं
class Symbol
def to_proc
Proc.new do |obj, *args|
obj.send self, *args
end
end
end
इस कोड के साथ, जब print [[1,'a'],[2,'b'],[3,'c']].map(&:first)
निष्पादित किया जाता है, रूबी [1,'a']
1 में पहला इनपुट और 'a' को obj
1 और args*
'a' को एक त्रुटि का कारण बनाता है क्योंकि Fixnum ऑब्जेक्ट 1 में स्वयं विधि नहीं है (जो है: पहला)।
जब [[1,'a'],[2,'b'],[3,'c']].map(&:first)
निष्पादित किया जाता है;
:first
एक प्रतीक वस्तु है, इसलिए जब &:first
एक पैरामीटर के रूप में मानचित्र विधि को दिया जाता है , तो Symbol # to_proc लागू किया जाता है।
मानचित्र कॉल मैसेज भेजता है: पैरामीटर के साथ first.to_proc [1,'a']
, उदाहरण के लिए, :first.to_proc.call([1,'a'])
निष्पादित किया जाता है।
प्रतीक में to_proc प्रक्रिया कक्षा के लिए एक सरणी वस्तु ( [1,'a']
) के साथ एक संदेश भेजता है पैरामीटर (: पहला), उदाहरण के लिए, [1,'a'].send(:first)
निष्पादित किया जाता है।
[[1,'a'],[2,'b'],[3,'c']]
ऑब्जेक्ट में बाकी तत्वों से अधिक पुनरावृत्त होता है ।
यह [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)
अभिव्यक्ति को निष्पादित करने के समान है ।
[1,2,3,4,5,6].inject(&:+)
- इंजेक्शन एक लैम्ब्डा की उम्मीद दो मापदंडों (मेमो और आइटम) से करता है और :+.to_proc
इसे डिलीवर करता है - Proc.new |obj, *args| { obj.send(self, *args) }
या{ |m, o| m.+(o) }
यहां दो चीजें हो रही हैं, और दोनों को समझना जरूरी है।
जैसा कि अन्य उत्तरों में वर्णित है, Symbol#to_proc
विधि कहा जा रहा है।
लेकिन इसका कारण to_proc
प्रतीक पर कहा जा रहा है क्योंकि इसे map
एक ब्लॉक तर्क के रूप में पारित किया जा रहा है। &
एक विधि कॉल में एक तर्क के सामने रखने से यह इस तरह से पारित हो जाता है। यह किसी भी रूबी विधि के लिए सही है, न कि केवल map
प्रतीकों के साथ।
def some_method(*args, &block)
puts "args: #{args.inspect}"
puts "block: #{block.inspect}"
end
some_method(:whatever)
# args: [:whatever]
# block: nil
some_method(&:whatever)
# args: []
# block: #<Proc:0x007fd23d010da8>
some_method(&"whatever")
# TypeError: wrong argument type String (expected Proc)
# (String doesn't respond to #to_proc)
Symbol
एक में परिवर्तित हो जाता Proc
है क्योंकि यह एक ब्लॉक के रूप में में पारित कर दिया है। हम एम्परसैंड के .map
बिना एक प्रॉप पास करने की कोशिश करके इसे दिखा सकते हैं :
arr = %w(apple banana)
reverse_upcase = proc { |i| i.reverse.upcase }
reverse_upcase.is_a?(Proc)
=> true
arr.map(reverse_upcase)
# ArgumentError: wrong number of arguments (1 for 0)
# (map expects 0 positional arguments and one block argument)
arr.map(&reverse_upcase)
=> ["ELPPA", "ANANAB"]
भले ही इसे परिवर्तित करने की आवश्यकता न हो, लेकिन विधि को इसका उपयोग करने का तरीका नहीं पता होगा क्योंकि यह एक ब्लॉक तर्क की अपेक्षा करता है। साथ इसे पारित &
देता .map
ब्लॉक यह उम्मीद है।
हालांकि हमारे पास पहले से ही शानदार जवाब हैं, एक शुरुआत के परिप्रेक्ष्य में देखकर मैं अतिरिक्त जानकारी जोड़ना चाहूंगा:
रूबी में मानचित्र (और: नाम) का क्या अर्थ है?
इसका मतलब है, कि आप मानचित्र फ़ंक्शन के पैरामीटर के रूप में एक और विधि पारित कर रहे हैं। (वास्तव में आप एक प्रतीक को पारित कर रहे हैं जो एक खरीद में परिवर्तित हो जाता है। लेकिन इस विशेष मामले में यह उतना महत्वपूर्ण नहीं है)।
जो महत्वपूर्ण है वह यह है कि आपके पास एक ऐसा method
नाम name
है जो मानचित्र विधि द्वारा पारंपरिक block
शैली के बजाय एक तर्क के रूप में उपयोग किया जाएगा ।
यह मूल रूप tag.name
से सरणी में प्रत्येक टैग पर विधि कॉल को निष्पादित करता है ।
यह एक सरलीकृत रूबी शॉर्टहैंड है।
सबसे पहले, के &:name
लिए एक शॉर्टकट है &:name.to_proc
, जहां :name.to_proc
एक रिटर्न Proc
(कुछ ऐसा ही है, लेकिन एक लैम्ब्डा के समान नहीं है) कि जब एक वस्तु के साथ कहा जाता है (पहली) तर्क, name
उस ऑब्जेक्ट पर विधि को कॉल करता है ।
दूसरे, धर्मान्तरित &
में जबकि def foo(&block) ... end
एक ब्लॉक पारित करने के foo
लिए Proc
, यह जब एक करने के लिए लागू विपरीत करता है Proc
।
इस प्रकार, &:name.to_proc
एक ब्लॉक है जो ऑब्जेक्ट को तर्क के रूप में लेता है और उस name
पर विधि कहता है, अर्थात { |o| o.name }
।
यह नीचे जैसा है:
def tag_names
if @tag_names
@tag_names
else
tags.map{ |t| t.name }.join(' ')
end