делать амперсанд для нескольких полей не работает в рубине - PullRequest
0 голосов
/ 12 мая 2018

В ruby ​​я могу сделать

['Hi', 'Yo'].map(&:upcase)

Но что, если я хочу получить одновременно и :upcase, и :downcase?

Ни то, ни другое

['Hi', 'Yo'].map(&[:upcase,:downcase])

ни

['Hi', 'Yo'].map([&:upcase,&:downcase])

работал.(

Ответы [ 3 ]

0 голосов
/ 12 мая 2018

Что у вас здесь:

['Hi', 'Yo'].map(&:upcase)

На самом деле это короткая версия:

['Hi', 'Yo'].map(&:upcase.to_proc)

Какой вариант:

['Hi', 'Yo'].map(&->(s) { s.send(:upcase) })

Или другими словами:

['Hi', 'Yo'].map { |s| s.upcase }

Обозначение &:x на самом деле является специальным сокращением для подобных ситуаций и работает только с единичным символом. Что вы можете сделать, это определить метод to_proc примерно так:

class Array
  def to_proc
    ->(i) { inject(i) { |v, m| v.send(m) } }
  end
end

Где этот метод должен возвращать объект Proc, "лямбду", который определен здесь с использованием нотации Ruby -> (...) { ... }.

Тогда вы можете назвать это так:

['Hi', 'Yo'].map(&[:upcase, :downcase, :to_sym].to_proc)
# => [:hi, :yo]
0 голосов
/ 12 мая 2018

Символ # to_proc полезен как сокращение для базового случая вызова одного метода.Если вы хотите что-то более сложное, просто перейдите на длинную строку

['Hi', 'Yo'].map { |word| [word.upcase, word.downcase] }

, которая вернет [['HI', 'hi'], ['YO', 'yo']] - которую вы могли бы затем назвать flatten, если вместо этого вы хотите ['HI', 'hi', 'YO', 'yo'].

ОБНОВЛЕНИЕ: Поскольку вы на самом деле хотите [['HI','YO'], ['hi', 'yo']], вы можете вызвать транспонирование для результатов

['Hi', 'Yo'].map { |w| [w.upcase, w.downcase] }.transpose

Примечание: следующее - ужасная идея, и никто не должен реализовывать ее в реальном коде, потому чтозначение Array # to_proc было бы совершенно неочевидным (вызывает ли он все и возвращает ли массив, выполняет ли он цепочку, передает ли параметры в метод и т. д.), но, поскольку вы запросили его, вы можете сделать что-то вроде

class Array
   def to_proc
     lambda { |o| map { |m| o.send(m) } }
   end
end

, что позволило бы

['Hi', 'Yo'].map(&[:upcase, :downcase]).transpose

дать ответ, который вы запрашиваете.Он сохраняет пару символов, но не стоит той двусмысленности, которую он добавляет к коду.

0 голосов
/ 12 мая 2018

&:symbol работает путем определения метода Symbol#to_proc.

Вот пример Symbol#to_proc, определенный в необработанном Ruby:

http://maximomussini.com/posts/ruby-to_proc/

class Symbol
  def to_proc
    ->(obj, args = nil) { obj.send(self, *args) }
  end
end

Версия C добавляет кэш, поэтому повторное создание блока каждый раз не замедляет нас.

Чтобы получить то, что вы хотите, определите Array#to_proc и получите его!

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