Entendendo o mapa#enumerável do rubi (com blocos mais complexos)
-
27-09-2019 - |
Pergunta
Digamos que eu tenho uma função
def odd_or_even n
if n%2 == 0
return :even
else
return :odd
end
end
E eu tinha uma variedade enumerável simples
simple = [1,2,3,4,5]
E eu o corri pelo mapa, com minha função, usando um bloco de ponta:
simple.map do
|n| odd_or_even(n)
end
# => [:odd,:even,:odd,:even,:odd]
Como eu poderia fazer isso sem, digamos, definir a função em primeiro lugar? Por exemplo,
# 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]
não é rubi válido, e o compilador fica bravo comigo por pensar nisso. Mas como eu implementaria um tipo de coisa equivalente, que funciona?
editar
Na realidade, a solução para o meu problema importa para mim muito menos do que a motivação/raciocínio por trás disso, para me ajudar a entender mais como os blocos de rubi funcionam :)
Solução
Você está tão perto. Basta remover o return
S e você é dourado.
Isso ocorre porque o bloco passou para map
é um Proc (ou seja, criado com Proc.new
), e não um lambda. UMA return
Dentro de um Proc, não sai apenas do proc- ele sai do método que executou (ou seja, chamou call
) o Proc. Um retorno dentro de um lambda, por outro lado, salta apenas do lambda.
o proc
O método retorna um Lambda no Ruby 1.8 e um Proc em Ruby 1.9. Provavelmente é melhor não usar esse método e ser explícito com qual construção você deseja usar.
Acho que você estava no IRB ou em um script rubi simples quando estava tentando isso.
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'
A lição para aprender com isso é usar retornos implícitos, a menos que você não possa, eu acho.
Outras dicas
Eu suspeito que essa pode ser uma pergunta duplicada, mas para dar um valor de um bloco, use next
simple.map do |n|
if n%2 == 0
next :even
else
next :odd
end
end
Variante mais curta usando a resposta de Andrew:
simple.map { |n| next :even if n % 2 == 0; :odd }