سؤال

لقد وجدت هذا الرمز في ريلزكاست:

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) يتم تنفيذ؛

  1. :first هو كائن رمز، لذلك متى &:first يتم إعطاء طريقة الخريطة كمعلمة، ويتم استدعاء الرمز #to_proc.

  2. ترسل الخريطة رسالة اتصال إلى:first.to_proc مع المعلمة [1,'a'], ، على سبيل المثال، :first.to_proc.call([1,'a']) يتم تنفيذ.

  3. يرسل إجراء to_proc في فئة الرمز رسالة إرسال إلى كائن صفيف ([1,'a']) مع المعلمة (:first)، على سبيل المثال، [1,'a'].send(:first) يتم تنفيذ.

  4. يتكرر على بقية العناصر في [[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
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top