Скажем, у меня есть функция
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]
не допустимый рубин, и компилятор рассердился на меня для того, чтобы даже думать об этом. Но как я реализовал бы эквивалентный вид вещи, которая работает?
править
В действительности решение моей проблемы имеет значение для меня намного меньше, чем мотивация/обоснование позади него, чтобы помочь мне понять больше, как работают рубиновые блоки :)
Вы так близко. Просто удалите return
, и вы золотой.
Это связано с тем, что блок, переданный в map
, является процедурой (т.е. создан с помощью Proc.new
), а не лямбда. return
внутри процедуры не просто выпрыгивает из процесса, он перескакивает из метода, который выполнил (то есть вызвал call
на) процедуры. С другой стороны, возврат внутри лямбды происходит только из лямбды.
Метод proc
возвращает лямбду в Ruby 1.8 и Proc в 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