Понимание Ruby перечислимо # карта (с более сложными блоками)

StackOverflow https://stackoverflow.com/questions/3042011

Вопрос

Скажем, у меня есть функция

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 }
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top