ماذا تعني الخريطة (&: الاسم) في روبي؟
-
07-07-2019 - |
سؤال
لقد وجدت هذا الرمز في ريلزكاست:
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
نصائح أخرى
والاختزال بارد آخر، غير معروف للكثيرين، هو
array.each(&method(:foo))
والذي هو اختصار ل
array.each { |element| foo(element) }
ومن خلال الدعوة method(:foo)
أخذنا كائن Method
من self
التي تمثل طريقة foo
لها، واستخدام &
للدلالة على أن لديها to_proc
<لأ href = "http://www.ruby-doc.org/core/Method أتش تي أم أل # طريقة ط to_proc "يختلط =" noreferrer "> طريقة أن يحوله إلى Proc
.
وهذا مفيد جدا عندما تريد أن تفعل أشياء <م> خالية من نقطة م> الاسلوب. مثال على ذلك هو للتحقق مما إذا كان هناك أي سلسلة في صفيف تساوي "foo"
السلسلة. وهناك الطريقة التقليدية:
["bar", "baz", "foo"].any? { |str| str == "foo" }
وهناك طريقة خالية من نقطة:
["bar", "baz", "foo"].any?(&"foo".method(:==))
ويجب أن تكون الطريقة المفضلة والأكثر قابلية للقراءة.
وانها ما يعادل
def tag_names
@tag_names || tags.map { |tag| tag.name }.join(' ')
end
وحين دعونا نلاحظ أيضا أن العطف #to_proc
السحر يمكن أن تعمل مع أي فئة، وليس مجرد رمز. العديد من Rubyists اختيار لتحديد #to_proc
على الطبقة صفيف:
class Array
def to_proc
proc { |receiver| receiver.send *self }
end
end
# And then...
[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]
وعلامة العطف &
يعمل عن طريق إرسال رسالة to_proc
في المعامل، والتي، في رمز أعلاه، هو من الطبقة صفيف. ومنذ أن كنت تعرف طريقة #to_proc
على صفيف، خط يصبح:
[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
وانها اختصار لtags.map { |tag| tag.name }.join(' ')
tags.map(&:name)
بالضبط مثل
tags.map{|tag| tag.name}
&:name
فقط يستخدم الرمز كاسم الطريقة المراد استدعاؤه.
إجابة جوش لي تكاد تكون صحيحة باستثناء أن رمز روبي المكافئ كان ينبغي أن يكون على النحو التالي.
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 و"أ" لإعطاء obj
1 و args*
'a' لإحداث خطأ لأن كائن Fixnum 1 لا يحتوي على الطريقة الذاتية (وهي: أولاً).
متى [[1,'a'],[2,'b'],[3,'c']].map(&:first)
يتم تنفيذ؛
:first
هو كائن رمز، لذلك متى&:first
يتم إعطاء طريقة الخريطة كمعلمة، ويتم استدعاء الرمز #to_proc.ترسل الخريطة رسالة اتصال إلى:first.to_proc مع المعلمة
[1,'a']
, ، على سبيل المثال،:first.to_proc.call([1,'a'])
يتم تنفيذ.يرسل إجراء to_proc في فئة الرمز رسالة إرسال إلى كائن صفيف (
[1,'a']
) مع المعلمة (:first)، على سبيل المثال،[1,'a'].send(:first)
يتم تنفيذ.يتكرر على بقية العناصر في
[[1,'a'],[2,'b'],[3,'c']]
هدف.
وهذا هو نفس التنفيذ [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first)
تعبير.
واثنين من الأشياء تحدث هنا، وأنه من المهم أن يفهم كل.
وكما هو موضح في إجابات أخرى، يتم استدعاء الأسلوب 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
كتلة انها تتوقع.
(و: الاسم) هي اختصار ل (و: name.to_proc) وهو نفس tags.map{ |t| t.name }.join(' ')
ويتم تنفيذ to_proc الواقع في C
وعلى الرغم من أن لدينا إجابات كبيرة بالفعل، وتبحث من خلال منظور مبتدئا أود أن إضافة معلومات إضافية:
<اقتباس فقرة>وماذا خريطة (و: الاسم)؟ يعني في روبي
اقتباس فقرة>وهذا يعني، أن يتم تمرير طريقة أخرى كمعلمة إلى وظيفة خريطة. (في الواقع كنت تمرير الرمز الذي يحصل على تحويلها إلى بروك. ولكن هذا ليس من المهم في هذه الحالة بالذات).
والمهم هو أن يكون لديك اسمه method
name
التي سيتم استخدامها من قبل طريقة خريطة كحجة بدلا من الاسلوب التقليدي block
.
الخريطة(&:الاسم) يأخذ كائنًا قابلاً للتعداد (العلامات في حالتك) ويقوم بتشغيل طريقة الاسم لكل عنصر/علامة، ويخرج كل قيمة تم إرجاعها من الطريقة.
وهو اختصار ل
array.map { |element| element.name }
الذي يقوم بإرجاع مجموعة من أسماء العناصر (العلامة).
وهنا :name
هو الرمز الذي أشر إلى name
طريقة الكائن العلامة.
عندما نعبر &:name
إلى map
، فإنه سيتم علاج name
ككائن بروك.
لفترة قصيرة، يعمل tags.map(&:name)
على النحو التالي:
tags.map do |tag|
tag.name
end
وهذا يعني
array.each(&:to_sym.to_proc)
وانها اساسا تنفيذ tag.name
استدعاء الأسلوب على كل العلامات في مجموعة.
ومن روبي الاختزال مبسط.
ومن نفس النحو التالي:
def tag_names
if @tag_names
@tag_names
else
tags.map{ |t| t.name }.join(' ')
end