Понимание Ruby перечислимо # карта (с более сложными блоками)
-
27-09-2019 - |
Вопрос
Скажем, у меня есть функция
def odd_or_even n
if n%2 == 0
return :even
else
return :odd
end
end
И у меня был простой перечислимый массив
simple = [1,2,3,4,5]
И я пробежал его через карту, с моей функцией, используя блок до конца:
simple.map do
|n| odd_or_even(n)
end
# => [:odd,:even,:odd,:even,:odd]
Как я мог сделать это без, скажем, определяя функцию в первую очередь? Например,
# does not work
simple.map do |n|
if n%2 == 0
return :even
else
return :odd
end
end
# Desired result:
# => [:odd,:even,:odd,:even,:odd]
Недействительно Ruby, и компилятор злится на меня, чтобы даже думать об этом. Но как бы я осуществил эквивалентную вещь, которая работает?
редактировать
На самом деле, решение моей проблемы имеет значение мне намного меньше, чем мотивация / рассуждение за ним, чтобы помочь мне понять, как Ruby Blocks работает :)
Решение
Ты такой близок. Просто удалите return
и ты золотой.
Это потому, что блок передан map
представляет собой proc (т.е. созданный с Proc.new
), а не лямбда. А. return
Внутри PROC не просто выпрыгивают из прочее, выпрыгивают из метода, который выполнен (то есть называется call
включено) Возвращение в пределах лямбда, с другой стороны, выпрыгивает только из лямбда.
То proc
Метод возвращает лямбда в Ruby 1.8, а в RUBY 1.9. Вероятно, лучше всего не использовать этот метод и быть явным, с которым вы хотите использовать конструкцию.
Я предполагаю, что вы были либо в IRB или простой скрипте Ruby, когда вы пробули это.
a = Proc.new { return }
a.call # fails. Nothing to return from.
def foobar
a = Proc.new { return }
a.call
puts 'hello' # not reached. The return within the proc causes execution to jump out of the foobar method.
end
foobar # succeeds, but does not print 'hello'. The return within the proc jumps out of the foobar method.
b = lambda { return }
b.call # succeeds. The return only returns from the lambda itself.
def bazquux
b = lambda { return }
b.call
puts 'hello' # this is reached. The lambda only returned from itself.
end
bazquux # succeeds, and prints 'hello'
Урок для изучения из этого является использование неявных возвратов, если вы не можете, я думаю.
Другие советы
Я подозреваю, что это может быть дубликатным вопросом, но для того, чтобы дать значение из блока, используйте next
simple.map do |n|
if n%2 == 0
next :even
else
next :odd
end
end
Самый короткий вариант с использованием ответа Эндрю:
simple.map { |n| next :even if n % 2 == 0; :odd }