मुझे यह कोड 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' को obj1 और 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