Зміст дописунатисність на посилання, щоб перейти до потрібного місця
У Ruby конструкція map(&:name) є скороченням для застосування методу до кожного елемента колекції. Ця форма використовується для того, щоб код був коротшим і більш читабельним. Розглянемо детальніше, що саме означає цей вираз.
Метод map використовується для проходження по кожному елементу колекції (ітерація) і виконання блоку коду для кожного елемента. У відповідь повертається новий масив з результатами виконання блоку.
[1, 2, 3].map { |n| n * 2 } # => [2, 4, 6]
Що означає &:name?
Ця (&:name у виразі array.map(&:name)) частина використовується для скорочення блоку, який викликає метод name для кожного елемента. Вона еквівалентна:
array.map { |item| item.name }
Тобто:
# Ось це: array.map { |item| item.name } # Та це: array.map(&:name) # Виконує одну й ту саму дію, але другий варіант має скорочений вигляд
Приклад
class User attr_accessor :name def initialize(name) @name = name end end users = [User.new('Alice'), User.new('Bob'), User.new('Charlie')] names = users.map(&:name) # => ["Alice", "Bob", "Charlie"] # Спробуємо 'довший' варіант names = users.map{ |user| user.name } # => ["Alice", "Bob", "Charlie"]
Як ми бачимо, обидва варіанти роблять одне й те саме. А що з перформансом? Давайте перевіремо бенчмарки.
Бенчмарки
require 'benchmark' class User attr_accessor :name def initialize(name) @name = name end end # Генерація великого масиву користувачів users = Array.new(100_000) { |i| User.new("User#{i}") } # Бенчмаркінг results = Benchmark.bm do |x| x.report('map(&:name)') do users.map(&:name) end x.report('map { |user| user.name }') do users.map { |user| user.name } end end puts results
Результат на моїй машині:
[#<Benchmark::Tms:0x000000010dd19ad0 @cstime=0.0, @cutime=0.0, @label="map(&:name)", @real=0.008466999977827072, @stime=0.00038199999999999346, @total=0.0077390000000007175, @utime=0.007357000000000724>, #<Benchmark::Tms:0x000000010dd19670 @cstime=0.0, @cutime=0.0, @label="map { |user| user.name }", @real=0.008027000352740288, @stime=0.0003069999999999462, @total=0.007962000000001468, @utime=0.007655000000001522>]
Взагалі, скорочений варіант більш оптимізований та швидкий. Але в моєму прикладі результат приблизно однаковий. Треба мати більш масивний набір даних, щоб бенчмарк показав різницю. Тож за замовчуванням, використовуйте скорочену (оптимізовану версію) виклику методу map. Можливо, зроблю окремий допис з бенчмарками.