Понимание Ruby Enumerable#map (с более сложными блоками)

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

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]

не допустимый рубин, и компилятор рассердился на меня для того, чтобы даже думать об этом. Но как я реализовал бы эквивалентный вид вещи, которая работает?

править

В действительности решение моей проблемы имеет значение для меня намного меньше, чем мотивация/обоснование позади него, чтобы помочь мне понять больше, как работают рубиновые блоки :)

5
задан Mohsen Nosratinia 8 May 2015 в 14:26
поделиться

2 ответа

Вы так близко. Просто удалите 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'

Урок, который следует извлечь из этого, состоит в том, чтобы использовать неявные возвраты, если вы не можете этого сделать, я полагаю.

13
ответ дан 18 December 2019 в 06:21
поделиться

Я подозреваю, что это может быть повторяющийся вопрос, но чтобы дать значение вне блока, используйте next

simple.map do |n|
  if n%2 == 0
    next :even
  else
    next :odd
  end
end
9
ответ дан 18 December 2019 в 06:21
поделиться
Другие вопросы по тегам:

Похожие вопросы: