Instrução de caso com vários valores em cada bloco 'when'


314

A melhor maneira de descrever o que estou procurando é mostrar o código com falha que tentei até agora:

case car
  when ['honda', 'acura'].include?(car)
    # code
  when 'toyota' || 'lexus'
    # code
end

Eu tenho cerca de 4 ou 5 whensituações diferentes que devem ser acionadas por aproximadamente 50 diferentes valores possíveis de car. Existe uma maneira de fazer isso com caseblocos ou devo tentar um ifbloco maciço ?

Respostas:


669

Em uma casedeclaração, a ,é o equivalente ||em uma ifdeclaração.

case car
   when 'toyota', 'lexus'
      # code
end

Algumas outras coisas que você pode fazer com uma declaração de caso Ruby


1
Este link tem um resumo melhor das instruções de caso em Ruby (e inclui exemplos da sintaxe regexp e splat também).
rsenna

Não sei porquê, mas esta situação estranha acontece: quando eu escrevo isto: when "toyota", "lexus", eu recebo: unexpected tSTRING_BEG, expecting keyword_do or '{' or '(' (SyntaxError). No entanto, quando escrevo isto when "toyota","lexus":, funciona. A única diferença é um espaço após vírgula.
quer

@FurkanAyhan Isso é estranho. Fui em frente e testei o código apenas para garantir que ele funcione. Meu palpite é que há algo mais acontecendo no seu código que está cometendo um erro assim. É possível que você tenha esquecido de fechar uma corda em algum lugar ou algo assim?
Charles Caldwell

1
Bem, isso funciona, mas como o Ruby se concentra na facilidade do programador, eu me pergunto por que ele não suporta o padrão || ou ou'? Isso é meio confuso
Zia Ul Rehman Mughal

2
Ruby não suporta orou ||aqui porque whenleva uma série de expressões separadas por vírgula à direita, e não um único identificador. Por esse motivo, se você tiver when a or b, não está claro se isso deve ser tomado como o equivalente de when a, bou when (a or b), o último dos quais avalia a expressão a or bprimeiro antes de jogá-la no quando. É mais surpreendente e menos fácil lidar com o idioma para ter tokens que mudam de comportamento com base no contexto e, portanto, você não seria capaz de usar uma orexpressão real no lado direito de um quando.
Taywee

99

Você pode tirar proveito da sintaxe "splat" ou achatada do ruby.

Isso faz com que as whencláusulas exageradas - você tem cerca de 10 valores para testar por filial, se bem entendi - um pouco mais legíveis na minha opinião. Além disso, você pode modificar os valores para testar em tempo de execução. Por exemplo:

honda  = ['honda', 'acura', 'civic', 'element', 'fit', ...]
toyota = ['toyota', 'lexus', 'tercel', 'rx', 'yaris', ...]
...

if include_concept_cars
  honda += ['ev-ster', 'concept c', 'concept s', ...]
  ...
end

case car
when *toyota
  # Do something for Toyota cars
when *honda
  # Do something for Honda cars
...
end

Outra abordagem comum seria usar um hash como uma tabela de despacho, com chaves para cada valor de care valores que são algum objeto que pode ser chamado, encapsulando o código que você deseja executar.


Isso é o que acabei usando, embora me sinta mal por tirar a marca de alguém: D
Nick

Solução brilhante para longas whenfilas. Obrigado por compartilhar.
Pistos

0

Outra boa maneira de colocar sua lógica nos dados é algo como isto:

# Initialization.
CAR_TYPES = {
  foo_type: ['honda', 'acura', 'mercedes'],
  bar_type: ['toyota', 'lexus']
  # More...
}
@type_for_name = {}
CAR_TYPES.each { |type, names| names.each { |name| @type_for_name[type] = name } }

case @type_for_name[car]
when :foo_type
  # do foo things
when :bar_type
  # do bar things
end

Não pretendo ser grosseiro, mas diminuí a votação porque isso é menos eficiente no tempo e no espaço. Também é mais complexo e menos legível do que as outras duas respostas. Qual seria o benefício de usar esse método?
Nick

Ele coloca toda a sua classificação em um único objeto. Agora você pode fazer coisas com esse objeto, como serializá-lo e enviá-lo a outra pessoa para explicar sua lógica, ou armazená-lo em um banco de dados e permitir que as pessoas o editem. (A lógica mudará muito em breve quando novos modelos de carros forem lançados, certo?) Você pode procurar "orientado à mesa".
Hew Wolff

YAGNI ("Você não vai precisar disso") pode se inscrever aqui. O design sacrifica a eficiência e a legibilidade do tempo / espaço para um cenário que pode existir no futuro, mas ainda não existe. O custo é pago agora, mas a recompensa pode nunca ser obtida.
Nick
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.