Сокращение для функций для сопоставления - PullRequest
9 голосов
/ 25 февраля 2012

В map я могу вызвать метод для переданного значения, используя удобную запись &::

nums = (0..10).to_a
strs = nums.map(&:to_s)

Есть ли что-то похожее для вызова функции со значением, переданным вв качестве первого аргумента?

nums = (0..10).to_a
nums.each(puts) # error!

Ответы [ 4 ]

11 голосов
/ 25 февраля 2012

Отказ от ответственности: Этот пост является чисто образовательным. nums.each {|n| puts n} действительно единственная разумная вещь, которую можно написать в реальном проекте.

Понимание nums.map(&:to_s)

Существующая краткая форма работает очень просто. & вызывает to_proc для символа, а to_proc для символа определяется следующим образом.

class Symbol
  def to_proc
    Proc.new { |*args| args.shift.__send__(self, *args) }
  end
end

Так как этот процесс начнет действовать как обычный блок, который передается в карту, *args в этом случае - это действительно каждый элемент, через который мы итерируем. Мы берем первое из аргументов (поскольку * превращает аргументы в массив) и отправляем ему self, self - фактический символ, такой как :to_s. Остальные аргументы передаются. Это как сказать nums.map{ |*args| args.shift.__send__(:to_s, *args) }.

Изменение его для включения nums.each(&:puts)

Мы могли бы легко реализовать to_proc, чтобы действовать по-другому. Вот быстрый пример.

class Symbol
  def to_proc
    Proc.new { |*args| __send__(self, *args) }
  end
end

(1..10).each(&:print) # => 12345678910

Здесь вместо того, чтобы отправлять имя символа в качестве сообщения элементу, мы просто вызываем символ как метод в текущем контексте и просто передаем итерированный элемент в качестве аргумента ему.

Так что это больше похоже на высказывание (1..10).each{|*args| __send__(:print, *args)}.

Понимание nums.each(&method(:puts))

Тем не менее, как отметил Нэш, вы можете позвонить nums.each(&method(:puts)). В результате вы получаете объект, представляющий метод puts с использованием метода method в ruby. Тогда & вызывает .to_proc для объекта метода, превращая его в proc, который сам начинает играть роль блока, переданного в each (или map). Аргументы, передаваемые в этот процесс (каждый элемент, который вы перебираете), затем становятся аргументами этого метода. Ухоженная.

Реализация xargs

Чтобы избежать перезаписи стандартного поведения, мы могли бы гипотетически реализовать нашу собственную функцию xargs, как в сценариях оболочки. (Не делай этого дома, слишком умный - плохо.)

class Symbol
  def to_xargs
    Proc.new{ |*args| __send__(self, *args) }
  end
end

def xargs(sym)
  sym.to_xargs
end

(1..10).each(&xargs(:print)) # prints 12345678910
9 голосов
/ 25 февраля 2012

используйте это:

nums.each(&method(:puts))

но на самом деле это не намного короче:)

2 голосов
/ 25 февраля 2012

Не совсем похоже, но как насчет:

nums.each {|n| puts n}
0 голосов
/ 03 июня 2014

На самом деле, когда puts получает массив, он печатает каждый элемент в новой строке ...

Записывает данные объекты в ios как с IO # print,Записывает разделитель записей (обычно это новая строка) после любого, который еще не заканчивается последовательностью новой строки. При вызове с аргументом массива записывает каждый элемент в новую строку .Если вызывается без аргументов, выводит один разделитель записей.

Итак ...

puts nums
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...