Como escrevo uma switch
declaração em Ruby?
Como escrevo uma switch
declaração em Ruby?
Respostas:
Ruby usa a case
expressão .
case x
when 1..5
"It's between 1 and 5"
when 6
"It's 6"
when "foo", "bar"
"It's either foo or bar"
when String
"You passed a string"
else
"You gave me #{x} -- I have no idea what to do with that."
end
Ruby compara o objeto na when
cláusula com o objeto na case
cláusula usando o ===
operador. Por exemplo,, 1..5 === x
e não x === 1..5
.
Isso permite when
cláusulas sofisticadas, como visto acima. Intervalos, classes e todo tipo de coisa podem ser testados em vez de apenas igualdade.
Diferentemente das switch
declarações em muitos outros idiomas, o Ruby case
não tem falhas , portanto, não há necessidade de terminar cada when
um com a break
. Você também pode especificar várias correspondências em uma única when
cláusula, como when "foo", "bar"
.
when
e return
na mesma linha:when "foo" then "bar"
switch
declarações em muitos outros idiomas, o Ruby's case
NÃO possui falhas , portanto, não há necessidade de terminar cada when
um com a break
.
then
. Por favor, veja também as outras respostas.
case...when
se comporta um pouco inesperadamente ao lidar com classes. Isso se deve ao fato de ele usar o ===
operador.
Esse operador trabalha como esperado com literais, mas não com classes:
1 === 1 # => true
Fixnum === Fixnum # => false
Isso significa que se você quiser fazer uma case ... when
classe sobre um objeto, isso não funcionará:
obj = 'hello'
case obj.class
when String
print('It is a string')
when Fixnum
print('It is a number')
else
print('It is not a string or number')
end
Irá imprimir "Não é uma string ou número".
Felizmente, isso é facilmente resolvido. O ===
operador foi definido para que retorne true
se você o usar com uma classe e fornecer uma instância dessa classe como o segundo operando:
Fixnum === 1 # => true
Em resumo, o código acima pode ser corrigido removendo o .class
:
obj = 'hello'
case obj # was case obj.class
when String
print('It is a string')
when Fixnum
print('It is a number')
else
print('It is not a string or number')
end
Encontrei esse problema hoje ao procurar uma resposta, e essa foi a primeira página que apareceu, então achei que seria útil para outras pessoas na mesma situação.
.class
parte É interessante notar, obrigado. Claro, esse é um comportamento inteiramente apropriado (embora eu pudesse ver como seria um erro comum pensar que isso seria impresso It is a string
) ... você está testando a classe de algum objeto arbitrário, não o próprio objeto. Assim, por exemplo: case 'hello'.class when String then "String!" when Class then "Class!" else "Something else" end
resulta em: "Class!"
Isso funciona da mesma para 1.class
, {}.class
, etc. deixando cair .class
, temos "String!"
ou "Something else"
para estes vários valores.
Isso é feito usando case
Ruby. Veja também " Alternar declaração " na Wikipedia.
Citado:
case n
when 0
puts 'You typed zero'
when 1, 9
puts 'n is a perfect square'
when 2
puts 'n is a prime number'
puts 'n is an even number'
when 3, 5, 7
puts 'n is a prime number'
when 4, 6, 8
puts 'n is an even number'
else
puts 'Only single-digit numbers are allowed'
end
Outro exemplo:
score = 70
result = case score
when 0..40 then "Fail"
when 41..60 then "Pass"
when 61..70 then "Pass with Merit"
when 71..100 then "Pass with Distinction"
else "Invalid Score"
end
puts result
Na página 123 da Linguagem de programação Ruby (1ª edição, O'Reilly) no meu Kindle, ele diz que a then
palavra - chave após as when
cláusulas pode ser substituída por uma nova linha ou ponto e vírgula (como na if then else
sintaxe). (O Ruby 1.8 também permite dois pontos no lugar de then
, mas essa sintaxe não é mais permitida no Ruby 1.9.)
when (-1.0/0.0)..-1 then "Epic fail"
type = #{score}
cada linha, posso simplesmente copiar o que você fez. Muito mais elegante que eu também gosto do one-liners muito melhor (se possível)
Para adicionar mais exemplos à resposta de Chuck :
Com parâmetro:
case a
when 1
puts "Single value"
when 2, 3
puts "One of comma-separated values"
when 4..6
puts "One of 4, 5, 6"
when 7...9
puts "One of 7, 8, but not 9"
else
puts "Any other thing"
end
Sem parâmetro:
case
when b < 3
puts "Little than 3"
when b == 3
puts "Equal to 3"
when (1..10) === b
puts "Something in closed range of [1..10]"
end
Por favor, esteja ciente de " Como escrever uma instrução switch em Ruby " sobre a qual o kikito alerta.
or
Muitas linguagens de programação, especialmente as derivadas de C, têm suporte para o chamado Switch Fallthrough . Eu estava procurando a melhor maneira de fazer o mesmo no Ruby e achei que poderia ser útil para outras pessoas:
Em idiomas do tipo C, o avanço geralmente se parece com isso:
switch (expression) {
case 'a':
case 'b':
case 'c':
// Do something for a, b or c
break;
case 'd':
case 'e':
// Do something else for d or e
break;
}
No Ruby, o mesmo pode ser alcançado da seguinte maneira:
case expression
when 'a', 'b', 'c'
# Do something for a, b or c
when 'd', 'e'
# Do something else for d or e
end
Isso não é estritamente equivalente, porque não é possível 'a'
executar um bloco de código antes de passar para 'b'
ou 'c'
, mas, na maioria das vezes, acho semelhante o suficiente para ser útil da mesma maneira.
No Ruby 2.0, você também pode usar lambdas em case
instruções, da seguinte maneira:
is_even = ->(x) { x % 2 == 0 }
case number
when 0 then puts 'zero'
when is_even then puts 'even'
else puts 'odd'
end
Você também pode criar seus próprios comparadores facilmente usando um Struct com um personalizado ===
Moddable = Struct.new(:n) do
def ===(numeric)
numeric % n == 0
end
end
mod4 = Moddable.new(4)
mod3 = Moddable.new(3)
case number
when mod4 then puts 'multiple of 4'
when mod3 then puts 'multiple of 3'
end
(Exemplo extraído de "Os procs podem ser usados com instruções de caso no Ruby 2.0? ".)
Ou, com uma aula completa:
class Vehicle
def ===(another_vehicle)
self.number_of_wheels == another_vehicle.number_of_wheels
end
end
four_wheeler = Vehicle.new 4
two_wheeler = Vehicle.new 2
case vehicle
when two_wheeler
puts 'two wheeler'
when four_wheeler
puts 'four wheeler'
end
(Exemplo retirado de " Como uma declaração de caso Ruby funciona e o que você pode fazer com ela ".)
Você pode usar expressões regulares, como encontrar um tipo de sequência:
case foo
when /^(true|false)$/
puts "Given string is boolean"
when /^[0-9]+$/
puts "Given string is integer"
when /^[0-9\.]+$/
puts "Given string is float"
else
puts "Given string is probably string"
end
Ruby case
usará o operando de igualdade ===
para isso (obrigado @ JimDeville). Informações adicionais estão disponíveis em " Ruby Operators ". Isso também pode ser feito usando o exemplo @mmdemirbas (sem parâmetro), apenas essa abordagem é mais limpa para esses tipos de casos.
Se você está ansioso para saber como usar uma condição OR em um caso de switch Ruby:
Portanto, em uma case
declaração, a ,
é equivalente a ||
em uma if
declaração.
case car
when 'Maruti', 'Hyundai'
# Code here
end
Consulte " Como uma declaração de caso Ruby funciona e o que você pode fazer com ela ".
É chamado case
e funciona como você esperaria, além de muito mais coisas divertidas, cortesia da ===
qual implementa os testes.
case 5
when 5
puts 'yes'
else
puts 'else'
end
Agora, para se divertir:
case 5 # every selector below would fire (if first)
when 3..7 # OK, this is nice
when 3,4,5,6 # also nice
when Fixnum # or
when Integer # or
when Numeric # or
when Comparable # (?!) or
when Object # (duhh) or
when Kernel # (?!) or
when BasicObject # (enough already)
...
end
E acontece que você também pode substituir uma cadeia if / else arbitrária (ou seja, mesmo que os testes não envolvam uma variável comum) case
deixando de fora o case
parâmetro inicial e escrevendo expressões onde a primeira correspondência é o que você deseja.
case
when x.nil?
...
when (x.match /'^fn'/)
...
when (x.include? 'substring')
...
when x.gsub('o', 'z') == 'fnzrq'
...
when Time.now.tuesday?
...
end
Ruby usa o case
para escrever instruções de opção.
Conforme a case
documentação:
As instruções de caso consistem em uma condição opcional, que está na posição de um argumento para
case
, e zero ou maiswhen
cláusulas. A primeirawhen
cláusula para corresponder à condição (ou para avaliar a verdade booleana, se a condição for nula) "vence" e sua estrofe de código é executada. O valor da instrução de caso é o valor dawhen
cláusula bem-sucedida ou,nil
se não houver,.Uma declaração de caso pode terminar com uma
else
cláusula. Cadawhen
declaração pode ter vários valores candidatos, separados por vírgulas.
Exemplo:
case x
when 1,2,3
puts "1, 2, or 3"
when 10
puts "10"
else
puts "Some other number"
end
Versão mais curta:
case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then puts "10"
else puts "Some other number"
end
E como " declaração de caso de Ruby - técnicas avançadas " descreve Ruby case
;
Pode ser usado com intervalos :
case 5
when (1..10)
puts "case statements match inclusion in a range"
end
## => "case statements match inclusion in a range"
Pode ser usado com o Regex :
case "FOOBAR"
when /BAR$/
puts "they can match regular expressions!"
end
## => "they can match regular expressions!"
Pode ser usado com Procs e Lambdas :
case 40
when -> (n) { n.to_s == "40" }
puts "lambdas!"
end
## => "lambdas"
Além disso, pode ser usado com suas próprias classes de correspondência:
class Success
def self.===(item)
item.status >= 200 && item.status < 300
end
end
class Empty
def self.===(item)
item.response_size == 0
end
end
case http_response
when Empty
puts "response was empty"
when Success
puts "response was a success"
end
Dependendo do seu caso, você pode preferir usar um hash de métodos.
Se houver uma longa lista de se when
cada um deles tiver um valor concreto para comparar (não um intervalo), será mais eficaz declarar um hash de métodos e depois chamar o método relevante a partir desse hash.
# Define the hash
menu = {a: :menu1, b: :menu2, c: :menu2, d: :menu3}
# Define the methods
def menu1
puts 'menu 1'
end
def menu2
puts 'menu 2'
end
def menu3
puts 'menu3'
end
# Let's say we case by selected_menu = :a
selected_menu = :a
# Then just call the relevant method from the hash
send(menu[selected_menu])
Como switch case
sempre retorna um único objeto, podemos imprimir diretamente seu resultado:
puts case a
when 0
"It's zero"
when 1
"It's one"
end
Caso com vários valores quando e sem valor:
print "Enter your grade: "
grade = gets.chomp
case grade
when "A", "B"
puts 'You pretty smart!'
when "C", "D"
puts 'You pretty dumb!!'
else
puts "You can't even use a computer!"
end
E uma solução de expressão regular aqui:
print "Enter a string: "
some_string = gets.chomp
case
when some_string.match(/\d/)
puts 'String has numbers'
when some_string.match(/[a-zA-Z]/)
puts 'String has letters'
else
puts 'String has no numbers or letters'
end
case some_string, when /\d/, (stuff), when /[a-zA-Z]/, (stuff), end
(onde ,
os meios de nova linha)
Você pode escrever case
expressões de duas maneiras diferentes no Ruby:
if
declaraçõescase
cada when
cláusula é comparada ao destino.age = 20
case
when age >= 21
puts "display something"
when 1 == 0
puts "omg"
else
puts "default condition"
end
ou:
case params[:unknown]
when /Something/ then 'Nothing'
when /Something else/ then 'I dont know'
end
Muitas ótimas respostas, mas pensei em adicionar um factóide. Se você estiver tentando comparar objetos (Classes), verifique se você tem um método de nave espacial (não uma piada) ou entenda como eles estão sendo comparados.
" Igualdade de Ruby e comparação de objetos " é uma boa discussão sobre o assunto.
<=>
é usado para retornar -1, 0, 1 ou zero, dependendo se a comparação retorna menos que, igual, maior que ou não comparável, respectivamente. A documentação do módulo Comparable do Ruby explica isso.
Conforme declarado em muitas das respostas acima, o ===
operador é usado sob o capô case
/ when
declarações.
Aqui estão informações adicionais sobre esse operador:
===
Muitas das classes internas do Ruby, como String, Range e Regexp, fornecem suas próprias implementações do ===
operador, também conhecidas como "igualdade de caso", "igual a triplo" ou "três a igual". Como é implementado de maneira diferente em cada classe, ele se comportará de maneira diferente, dependendo do tipo de objeto em que foi chamado. Geralmente, ele retornará true se o objeto à direita "pertencer a" ou "for um membro" do objeto à esquerda. Por exemplo, ele pode ser usado para testar se um objeto é uma instância de uma classe (ou uma de suas subclasses).
String === "zen" # Output: => true
Range === (1..2) # Output: => true
Array === [1,2,3] # Output: => true
Integer === 2 # Output: => true
O mesmo resultado pode ser alcançado com outros métodos que provavelmente são mais adequados para o trabalho, como is_a?
einstance_of?
.
===
Quando o ===
operador é chamado em um objeto de intervalo, ele retorna true se o valor à direita estiver dentro do intervalo à esquerda.
(1..4) === 3 # Output: => true
(1..4) === 2.345 # Output: => true
(1..4) === 6 # Output: => false
("a".."d") === "c" # Output: => true
("a".."d") === "e" # Output: => false
Lembre-se de que o ===
operador chama o ===
método do objeto esquerdo. Então (1..4) === 3
é equivalente a (1..4).=== 3
. Em outras palavras, a classe do operando esquerdo definirá qual implementação do ===
método será chamada, de modo que as posições do operando não serão intercambiáveis.
===
Retorna true se a sequência à direita corresponder à expressão regular à esquerda.
/zen/ === "practice zazen today" # Output: => true
# is similar to
"practice zazen today"=~ /zen/
A única diferença relevante entre os dois exemplos acima é que, quando há uma correspondência, ===
retorna true e =~
retorna um número inteiro, que é um valor verdadeiro em Ruby. Voltaremos a isso em breve.
puts "Recommend me a language to learn?"
input = gets.chomp.downcase.to_s
case input
when 'ruby'
puts "Learn Ruby"
when 'python'
puts "Learn Python"
when 'java'
puts "Learn Java"
when 'php'
puts "Learn PHP"
else
"Go to Sleep!"
end
$age = 5
case $age
when 0 .. 2
puts "baby"
when 3 .. 6
puts "little child"
when 7 .. 12
puts "child"
when 13 .. 18
puts "youth"
else
puts "adult"
end
Consulte " Ruby - se ... mais, caso, a menos " para obter mais informações.
Comecei a usar:
a = "secondcase"
var_name = case a
when "firstcase" then "foo"
when "secondcase" then "bar"
end
puts var_name
>> "bar"
Ajuda o código compacto em alguns casos.
Hash
uma case
instrução , e não uma instrução.
Não há suporte para expressões regulares em seu ambiente? Por exemplo, Editor de scripts do Shopify (abril de 2018):
[Erro]: RegExp constante não inicializada
Uma solução alternativa após uma combinação de métodos já abordados anteriormente aqui e aqui :
code = '!ADD-SUPER-BONUS!'
class StrContains
def self.===(item)
item.include? 'SUPER' or item.include? 'MEGA' or\
item.include? 'MINI' or item.include? 'UBER'
end
end
case code.upcase
when '12345PROMO', 'CODE-007', StrContains
puts "Code #{code} is a discount code!"
when '!ADD-BONUS!'
puts 'This is a bonus code!'
else
puts 'Sorry, we can\'t do anything with the code you added...'
end
Eu usei or
s na instrução de método de classe, pois ||
tem maior precedência que
.include?
. Se você é um rubi-nazista , imagine que eu usei isso (item.include? 'A') || ...
. teste repl.it.
É essencial enfatizar a vírgula ( ,
) em uma when
cláusula. Ele atua como um ||
de uma if
declaração, ou seja, ele faz um OR comparação e não um E comparação entre as expressões delimitados da when
cláusula. Veja a seguinte declaração de caso:
x = 3
case x
when 3, x < 2 then 'apple'
when 3, x > 2 then 'orange'
end
=> "apple"
x
não é menor que 2, mas o valor de retorno é "apple"
. Por quê? Porque x
tinha 3 anos e desde ',`` acts as an
|| , it did not bother to evaluate the expression
x <2 '.
Você pode pensar que, para executar um AND , pode fazer algo como isto abaixo, mas não funciona:
case x
when (3 && x < 2) then 'apple'
when (3 && x > 2) then 'orange'
end
=> nil
Não funciona porque é (3 && x > 2)
avaliado como verdadeiro, e Ruby pega o valor True e o compara x
com o ===
que não é verdadeiro, pois x
é 3.
Para fazer uma &&
comparação, você terá que tratar case
como um bloco if
/ else
:
case
when x == 3 && x < 2 then 'apple'
when x == 3 && x > 2 then 'orange'
end
No livro Ruby Programming Language, Matz diz que esse último formulário é simples (e raramente usado), que nada mais é do que uma sintaxe alternativa para if
/ elsif
/ else
. No entanto, se é pouco usado ou não, não vejo outra maneira de anexar várias &&
expressões para uma determinada when
cláusula.
if...elsif
? Parece que você está tentando misturar uma declaração de caso e uma condição. Por quê? Basta colocar a condicional dentro do bloco when, por exemplo. when 3; ( x < 2 ) ? 'apple' : 'orange'
Podemos escrever a instrução switch para várias condições.
Por exemplo,
x = 22
CASE x
WHEN 0..14 THEN puts "#{x} is less than 15"
WHEN 15 THEN puts "#{x} equals 15"
WHEN 15 THEN puts "#{x} equals 15"
WHEN 15..20 THEN puts "#{x} is greater than 15"
ELSE puts "Not in the range, value #{x} "
END
case
, when
, end
) São maiúsculas de minúsculas e não pode ser maiúscula como esta.
NoMethodError (undefined method
CASE 'para main: Object) `. Como @ sondra.kinsey disse, você não pode usar maiúsculas. Ruby achará que é um CONSTANTE.
O case
operador de instrução é comoswitch
nos outros idiomas.
Esta é a sintaxe de switch...case
em C:
switch (expression)
{
case constant1:
// statements
break;
case constant2:
// statements
break;
.
.
.
default:
// default statements
}
Esta é a sintaxe do case...when
Ruby:
case expression
when constant1, constant2 #Each when statement can have multiple candidate values, separated by commas.
# statements
next # is like continue in other languages
when constant3
# statements
exit # exit is like break in other languages
.
.
.
else
# statements
end
Por exemplo:
x = 10
case x
when 1,2,3
puts "1, 2, or 3"
exit
when 10
puts "10" # it will stop here and execute that line
exit # then it'll exit
else
puts "Some other number"
end
Para mais informações, consulte a case
documentação.