Вы, вероятно, знакомы со следующей сокращенной записью Ruby ( a
это массив):
a.map(&:method)
Например, попробуйте в irb следующее:
>> a=[:a, 'a', 1, 1.0]
=> [:a, "a", 1, 1.0]
>> a.map(&:class)
=> [Symbol, String, Fixnum, Float]
Синтаксис a.map(&:class)
является сокращением для a.map {|x| x.class}
.
Подробнее об этом синтаксисе читайте в разделе « Что означает map (&: name) в Ruby? ».
С помощью синтаксиса &:class
вы вызываете метод class
для каждого элемента массива.
Мой вопрос: можете ли вы предоставить аргументы для вызова метода? И если да, то как?
Например, как преобразовать следующий синтаксис
a = [1,3,5,7,9]
a.map {|x| x + 2}
к &:
синтаксису?
Я не утверждаю, что &:
синтаксис лучше. Меня просто интересует механизм использования &:
синтаксиса с аргументами.
Я предполагаю, что вы знаете, что +
это метод класса Integer. В irb можно попробовать следующее:
>> a=1
=> 1
>> a+(1)
=> 2
>> a.send(:+, 1)
=> 2
Symbol#with
может не существовать в основной библиотеке и определение этого метода менее разрушительно, чем переопределение существующего метода, оно все же изменяет (т.е. перезаписывает) реализацию основного класса библиотеки ruby. Практика должна выполняться очень экономно и с большой осторожностью. \ n \ n Пожалуйста, рассмотрите возможность наследования существующего класса и изменения вновь созданного класса. Как правило, это дает сопоставимые результаты без отрицательных побочных эффектов изменения основных классов рубинов.Symbol
класс - это нетривиально (если даже возможно), поскольку это такой базовый класс (например, у него нетnew
метода), и его использование будет громоздким (если даже возможно), что победит цель улучшения ... если вы можете показать реализацию, которая использует это и дает сопоставимые результаты - поделитесь, пожалуйста!with
метода определитеcall
. Затем вы можете делать такие вещи, как,a.map(&:+.(2))
посколькуobject.()
использует#call
метод. И пока вы:+.(2).(3) #=> 5
занимаетесь этим, вы можете писать забавные вещи вроде ... похоже на LISPy, не так ли?По вашему примеру можно сделать
a.map(&2.method(:+))
.Вот как это работает :-
2.method(:+)
даетMethod
объект. Затем&
, на2.method(:+)
самом деле вызов#to_proc
метода, который делает егоProc
объектом. Затем следуйте инструкциям. Как вы называете оператор &: в Ruby? ,источник
Pry
результаты выше, вы можете понять, как это работает.+
он коммутативен.Как подтверждает сообщение, на которое вы ссылаетесь,
a.map(&:class)
это не сокращение,a.map {|x| x.class}
а дляa.map(&:class.to_proc)
.Это означает, что
to_proc
вызывается все, что следует за&
оператором.Таким образом, вы можете дать ему
Proc
вместо этого:Я знаю, что, скорее всего, это противоречит цели вашего вопроса, но я не вижу другого выхода - дело не в том, что вы указываете, какой метод вызывать, вы просто передаете ему то, на что отвечает
to_proc
.источник
my_proc = Proc.new{|i| i + 1}
,[1,2,3,4].map(&my_proc) => [2,3,4,5]
Короткий ответ: Нет.
Следуя ответу @ rkon, вы также можете сделать это:
источник
&->(_){_ + 2}
короче{|x| x + 2}
.Есть еще одна нативная опция для enumerables, которая, на мой взгляд, хороша только для двух аргументов. у класса
Enumerable
есть метод,with_object
который затем возвращает другойEnumerable
.Таким образом, вы можете вызвать
&
оператор для метода с каждым элементом и объектом в качестве аргументов.Пример:
Если вам нужно больше аргументов, вы должны повторить процесс, но, на мой взгляд, это некрасиво:
источник
Вместо того, чтобы самостоятельно исправлять базовые классы, как в принятом ответе, короче и чище использовать функциональность гема Facets :
источник
Я не уверен в том, что
Symbol#with
уже было опубликовано, я немного упростил его, и он хорошо работает:(также используется
public_send
вместо того,send
чтобы предотвратить вызов частных методов, такжеcaller
уже используется Ruby, поэтому это сбивало с толку)источник