ملخص - ماذا تعني الخريطة(&: name) في Ruby؟




ملخص html5 (9)

(&: name) اختصار لـ (&: name.to_proc) وهو نفس tags.map{ |t| t.name }.join(' ') tags.map{ |t| t.name }.join(' ')

يتم تنفيذ to_proc فعليًا في C

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

def tag_names
  @tag_names || tags.map(&:name).join(' ')
end

ماذا يعني (&:name) في map(&:name) ؟


اختزال آخر بارد ، غير معروف للكثيرين ، هو

array.each(&method(:foo))

وهو اختزال ل

array.each { |element| foo(element) }

عن طريق استدعاء method(:foo) أخذنا كائن Method من self الذي يمثل أسلوب foo الخاص به ، واستخدم & إلى الإشارة إلى أنه يحتوي على method to_proc الذي يحولها إلى Proc .

هذا مفيد جدا عندما تريد أن تفعل الاشياء بدون اسلوب. مثال على ذلك هو التحقق من وجود أي سلسلة في صفيف يساوي السلسلة "foo" . هناك الطريقة التقليدية:

["bar", "baz", "foo"].any? { |str| str == "foo" }

وهناك طريقة خالية من النقاط:

["bar", "baz", "foo"].any?(&"foo".method(:==))

يجب أن تكون الطريقة المفضلة هي الأكثر قابلية للقراءة.


اختصار لـ tags.map { |tag| tag.name }.join(' ') tags.map { |tag| tag.name }.join(' ')


الجواب جوش لي هو الصحيح تقريبا إلا أن رمز روبي يعادل ينبغي أن يكون على النحو التالي.

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) ، يقوم Ruby بتقسيم الإدخال الأول [1,'a'] إلى 1 و' a 'لإعطاء obj 1 و args* ' a 'للتسبب في حدوث خطأ لأن كائن Fixnum 1 لا يحتوي على الأسلوب self (وهو: first).

عندما يتم تنفيذ [[1,'a'],[2,'b'],[3,'c']].map(&:first) ؛

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

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

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

  4. يتكرر على باقي العناصر في [[1,'a'],[2,'b'],[3,'c']] الكائن.

هذا هو نفس تنفيذ [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first) تعبير.


على الرغم من أن لدينا إجابات رائعة بالفعل ، بالنظر إلى منظور المبتدئين ، فإنني أود إضافة المعلومات الإضافية:

ماذا تعني الخريطة (&: name) في Ruby؟

هذا يعني أنك تقوم بتمرير طريقة أخرى كمعلمة إلى وظيفة الخريطة. (في الواقع أنت تمر برمز يتم تحويله إلى proc. لكن هذا ليس مهمًا في هذه الحالة بالذات).

ما هو مهم هو أن لديك method باسم name سيتم استخدامها بواسطة طريقة الخريطة كوسيطة بدلاً من نمط block التقليدي.


في حين أننا نلاحظ أيضًا أن علامة #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!"]

to_proc العطف & يعمل عن طريق إرسال رسالة to_proc على المعامل الخاص به ، والتي ، في التعليمات البرمجية أعلاه ، من فئة الصفيف. ومنذ أن قمت بتعريف طريقة #to_proc في صفيف ، يصبح السطر:

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }

هنا :name هو الرمز الذي يشير إلى name أسلوب كائن العلامة. عندما نجتاز &:name to map ، فسوف تعامل name كجسم proc. باختصار ، tags.map(&:name) كـ:

tags.map do |tag|
  tag.name
end

هناك أمران يحدثان هنا ، ومن المهم فهمهما.

كما هو موضح في إجابات أخرى ، يتم استدعاء الأسلوب Symbol#to_proc .

ولكن يتم استدعاء السبب to_proc على الرمز لأنه يتم تمريره to_proc كوسيطة كتلة. يؤدي وضع وأمام وسيطة في استدعاء الأسلوب إلى تمريرها بهذه الطريقة. وينطبق ذلك على أي طريقة من طرق روبي ، وليس مجرد وضع 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 لأنه يتم تمريره ككتلة. يمكننا إظهار ذلك بمحاولة تمرير 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 الكتلة يتوقع.


tags.map(&:name)

بالضبط مثل

tags.map{|tag| tag.name}

&:name يستخدم &:name الرمز فقط كاسم الأسلوب المراد الاتصال به.







parameter-passing