switch-statement $var - Comment écrire une déclaration de commutateur dans Ruby?




somme create (18)

Comment écrire une instruction switch dans Ruby?


Answers

Vous pouvez utiliser des expressions régulières, telles que la recherche d'un type de chaîne:

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

Le case de Ruby utilisera l'opérande d'égalité === pour cela (merci @JimDeville). Des informations supplémentaires sont disponibles sur " Ruby Operators ". Cela peut également être fait en utilisant l'exemple @mmdemirbas (sans paramètre), seule cette approche est plus propre pour ces types de cas.


De nombreux langages de programmation, en particulier ceux dérivés du langage C, prennent en charge ce que l'on appelle le commutateur Fallthrough . Je cherchais le meilleur moyen de faire la même chose avec Ruby et je pensais que cela pourrait être utile aux autres:

Dans les langages en forme de C, le déroulement ressemble généralement à ceci:

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;
}

En Ruby, la même chose peut être réalisée de la façon suivante:

case expression
when 'a', 'b', 'c'
  # Do something for a, b or c
when 'd', 'e'
  # Do something else for d or e
end

Ce n'est pas strictement équivalent, car il n'est pas possible de laisser 'a' exécuter un bloc de code avant de passer à 'b' ou 'c' , mais pour la plupart, je le trouve assez similaire pour être utile de la même manière.



Dans Ruby 2.0, vous pouvez également utiliser lambdas dans les instructions de case , comme suit:

is_even = ->(x) { x % 2 == 0 }

case number
when 0 then puts 'zero'
when is_even then puts 'even'
else puts 'odd'
end

Vous pouvez également créer vos propres comparateurs facilement en utilisant un Struct avec un custom ===

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

(Exemple tiré de " Peut-on utiliser procs avec des instructions de cas dans Ruby 2.0? ".)

Ou, avec une classe complète:

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

(Exemple tiré de « Comment une déclaration de cas Ruby fonctionne et ce que vous pouvez faire avec »)


J'ai commencé à utiliser:

a = "secondcase"

var_name = case a
  when "firstcase" then "foo"
  when "secondcase" then "bar"
end

puts var_name
>> "bar"

Cela aide le code compact dans certains cas.


Ruby utilise le case pour écrire des instructions de commutation.

Selon les Ruby Docs :

Les instructions de cas sont constituées d'une condition optionnelle, qui est dans la position d'un argument à case , et de zéro ou plus when clauses. La première when clause pour correspondre à la condition (ou pour évaluer à la vérité booléenne, si la condition est nulle) "gagne", et sa strophe de code est exécutée. La valeur de l'instruction case est la valeur de la clause successful when ou nil s'il n'y a pas de clause.

Une instruction case peut se terminer par une clause else . Chaque when qu'une instruction peut avoir plusieurs valeurs candidates, séparées par des virgules.

Exemple:

case x
when 1,2,3
  puts "1, 2, or 3"
when 10
  puts "10"
else
  puts "Some other number"
end

Version plus courte:

case x
when 1,2,3 then puts "1, 2, or 3"
when 10 then puts "10"
else puts "Some other number"
end

Et comme ce blog de Honeybadger décrit Ruby Case;

Peut être utilisé avec des Ranges :

case 5
when (1..10)
  puts "case statements match inclusion in a range"
end

## => "case statements match inclusion in a range"

Peut être utilisé avec Regex :

case "FOOBAR"
when /BAR$/
  puts "they can match regular expressions!"
end

## => "they can match regular expressions!"

Peut être utilisé avec Procs et Lambda :

case 40
when -> (n) { n.to_s == "40" }
  puts "lambdas!"
end

## => "lambdas"

En outre, peut être utilisé avec vos propres classes de correspondance:

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

Vous pouvez faire comme ça de manière plus naturelle,

case expression
when condtion1
   function
when condition2
   function
else
   function
end

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

Pas de support pour les expressions régulières dans votre environnement? Par exemple, Shopify Script Editor (avril 2018):

[Erreur]: constante non initialisée RegExp

Une solution de contournement suite à une combinaison de méthodes déjà couvertes here et here :

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

J'ai utilisé or s dans la déclaration de méthode de classe depuis || a une plus grande priorité que .include? . Si vous êtes un ruby-nazi , imaginez que je l'ai utilisé (item.include? 'A') || ... (item.include? 'A') || ... place. test de repl.it


Ruby utilise l' expression de case place.

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 compare l'objet de la clause when avec l'objet de la clause case utilisant l'opérateur === . Par exemple, 1..5 === x , et non x === 1..5 .

Cela permet des clauses sophistiquées when vu ci-dessus. Les gammes, les classes et toutes sortes de choses peuvent être testées plutôt que simplement l'égalité.

Contrairement aux instructions de switch dans de nombreuses autres langues, le case de Ruby n'a pas de fall-through , il n'est donc pas nécessaire de terminer chaque when avec une break . Vous pouvez également spécifier plusieurs correspondances dans une seule clause when "foo", "bar" .


Beaucoup de bonnes réponses mais je pensais que j'ajouterais un factoid .. Si vous essayez de comparer des objets (Classes) assurez-vous que vous avez une méthode de vaisseau spatial (pas une blague) ou de comprendre comment ils sont comparés

Voici une bonne discussion sur le sujet http://www.skorks.com/2009/09/ruby-equality-and-object-comparison/


C'est ce qu'on appelle le case et cela fonctionne comme vous attendez, plus beaucoup de choses amusantes avec la permission de === qui implémente les tests.

case 5
  when 5
    puts 'yes'
  else
    puts 'else'
end

Maintenant pour s'amuser:

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

Et il se trouve que vous pouvez également remplacer une chaîne if / else arbitraire (c'est-à-dire, même si les tests n'impliquent pas une variable commune) avec case en omettant le paramètre case initial et en écrivant simplement des expressions où le premier correspond à vouloir.

case
  when x.nil?
    ...
  when (x.match /'^fn'/)
    ...
  when (x.include? 'substring')
    ...
  when x.gsub('o', 'z') == 'fnzrq'
    ...
  when Time.now.tuesday?
    ...
end


C'est fait par case en Ruby. Voir aussi cet article sur Wikipedia .

Cité:

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

Un autre exemple:

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

Sur la page 123 (j'utilise Kindle) de The Ruby Programming Lanugage (1ère édition, O'Reilly), il est dit que le mot-clé then suivant les clauses when peut être remplacé par un saut de ligne ou un point-virgule (comme dans la syntaxe if then else ). (Ruby 1.8 permet aussi un deux-points à la place de ... Mais cette syntaxe n'est plus autorisée dans Ruby 1.9.)


cas ... quand

Pour ajouter plus d'exemples à la réponse de Chuck :

Avec paramètre:

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

Sans paramètre:

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

S'il vous plaît, soyez conscient du problème que kikito met en garde.


case...when se comporte un peu de façon inattendue lors de la gestion des classes. Cela est dû au fait qu'il utilise l'opérateur === .

Cet opérateur fonctionne comme prévu avec des littéraux, mais pas avec des classes:

1 === 1           # => true
Fixnum === Fixnum # => false

Cela signifie que si vous voulez faire un case ... when dessus de la classe d'un objet, cela ne fonctionnera pas:

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')
end

Va imprimer "Ce n'est pas une chaîne".

Heureusement, ceci est facilement résolu. L'opérateur === a été défini de sorte qu'il renvoie true si vous l'utilisez avec une classe et fournissez une instance de cette classe en tant que second opérande:

Fixnum === 1 # => true

En bref, le code ci-dessus peut être corrigé en supprimant le .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')
end

J'ai rencontré ce problème aujourd'hui en cherchant une réponse, et c'était la première page qui apparaissait, alors j'ai pensé que cela serait utile aux autres dans la même situation.


Comme indiqué dans la plupart des réponses ci-dessus, l'opérateur === est utilisé sous le capot sur les déclarations cas / when.

Voici quelques informations supplémentaires sur cet opérateur.

Opérateur d'égalité de cas: ===

Beaucoup de classes intégrées de Ruby, telles que String, Range et Regexp, fournissent leurs propres implémentations de l'opérateur ===, également connu sous le nom d'égalité des cas, triple égal ou troisquals. Comme il est implémenté différemment dans chaque classe, il se comportera différemment selon le type d'objet sur lequel il a été appelé. Généralement, il renvoie true si l'objet de droite "appartient à" ou "est membre de" l'objet de gauche. Par exemple, il peut être utilisé pour tester si un objet est une instance d'une classe (ou d'une de ses sous-classes).

String === "zen"  # Output: => true
Range === (1..2)   # Output: => true
Array === [1,2,3]   # Output: => true
Integer === 2   # Output: => true

Le même résultat peut être obtenu avec d'autres méthodes qui sont probablement les mieux adaptées au travail, comme is_a? et instance_of ?.

Implémentation de la plage de ===

Lorsque l'opérateur === est appelé sur un objet range, il renvoie true si la valeur sur la droite se situe dans la plage de gauche.

(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

Souvenez-vous que l'opérateur === invoque la méthode === de l'objet de gauche. Donc (1..4) === 3 est équivalent à (1..4). === 3. En d'autres termes, la classe de l'opérande de gauche définira quelle implémentation de la méthode === sera appelé, de sorte que les positions d'opérande ne sont pas interchangeables.

Implémentation de Regexp de ===

Renvoie true si la chaîne de droite correspond à l'expression régulière sur la gauche. / zen / === "pratique zazen aujourd'hui" # Output: => true # est similaire à "zazen practice now" = ~ / zen /

La seule différence pertinente entre les deux exemples ci-dessus est que, quand il y a une correspondance, === renvoie true et = ~ renvoie un entier, ce qui est une valeur de vérité dans Ruby. Nous y reviendrons bientôt.


J'ai aussi fait face à ce problème et j'ai écrit une réponse assez longue à cette question. Il y a déjà d'excellentes réponses à ce sujet, mais si vous voulez plus de précisions, j'espère que ma réponse peut aider

Initialiser la méthode

Initialize vous permet de définir des données sur une instance d'un objet lors de la création de l'instance plutôt que de devoir les définir sur une ligne distincte dans votre code chaque fois que vous créez une nouvelle instance de la classe.

class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end


  def greeting
    "Hello #{@name}"
  end
end

person = Person.new("Denis")
puts person.greeting

Dans le code ci-dessus, nous définissons le nom "Denis" en utilisant la méthode initialize en passant Dennis à travers le paramètre dans Initialize. Si nous voulions définir le nom sans la méthode initialize, nous pourrions le faire comme ceci:

class Person
  attr_accessor :name

  # def initialize(name)
  #     @name = name
  # end

  def greeting
    "Hello #{name}"
  end
end

person = Person.new
person.name = "Dennis"
puts person.greeting

Dans le code ci-dessus, nous définissons le nom en appelant la méthode ens_accessor setter à l'aide de person.name, plutôt que de définir les valeurs lors de l'initialisation de l'objet.

Les deux "méthodes" de faire ce travail, mais initialiser nous économise du temps et des lignes de code.

C'est le seul travail d'initialisation. Vous ne pouvez pas appeler initialize en tant que méthode. Pour obtenir réellement les valeurs d'un objet d'instance, vous devez utiliser des getters et setters (attr_reader (get), attr_writer (set), et attr_accessor (both)). Voir ci-dessous pour plus de détails sur ceux-ci.

Getters, Setters (attr_reader, attr_writer, attr_accessor)

Getters, attr_reader: L'objectif global d'un getter est de renvoyer la valeur d'une variable d'instance particulière. Visitez l'exemple de code ci-dessous pour une ventilation à ce sujet.

class Item

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

  def item_name
    @item_name
  end

  def quantity
     @quantity
  end
end

example = Item.new("TV",2)
puts example.item_name
puts example.quantity

Dans le code ci-dessus vous appelez les méthodes "item_name" et "quantity" sur l'instance de Item "example". Les "puts.name name" et "example.quantity" retournera (ou "get") la valeur pour les paramètres qui ont été transmis dans le "exemple" et les afficher à l'écran.

Heureusement, dans Ruby, il existe une méthode inhérente qui nous permet d'écrire ce code plus succinctement; la méthode attr_reader. Voir le code ci-dessous

class Item

attr_reader :item_name, :quantity

  def initialize(item_name, quantity)
    @item_name = item_name
    @quantity = quantity
  end

end

item = Item.new("TV",2)
puts item.item_name
puts item.quantity

Cette syntaxe fonctionne exactement de la même manière, seulement elle nous sauve six lignes de code. Imaginez si vous aviez 5 états supplémentaires attribuables à la classe Item? Le code deviendrait rapidement.

Setters, attr_writer: Ce qui m'a bloqué au début avec les méthodes de setter, c'est qu'à mes yeux, il semblait avoir une fonction identique à la méthode initialize. Ci-dessous, j'explique la différence en fonction de ma compréhension.

Comme indiqué précédemment, la méthode initialize vous permet de définir les valeurs d'une instance d'un objet lors de sa création.

Mais que se passe-t-il si vous souhaitez définir les valeurs ultérieurement, après la création de l'instance, ou les modifier après leur initialisation? Ce serait un scénario où vous utiliseriez une méthode setter. C'EST LA DIFFÉRENCE. Vous n'avez pas besoin de "définir" un état particulier lorsque vous utilisez initialement la méthode attr_writer.

Le code ci-dessous est un exemple d'utilisation d'une méthode setter pour déclarer la valeur item_name pour cette instance de la classe Item. Notez que nous continuons à utiliser la méthode getter attr_reader afin que nous puissions obtenir les valeurs et les imprimer à l'écran, juste au cas où vous voudriez tester le code par vous-même.

class Item

attr_reader :item_name

  def item_name=(str)
    @item_name = (str)
  end

end

Le code ci-dessous est un exemple d'utilisation de attr_writer pour raccourcir encore une fois notre code et nous faire gagner du temps.

class Item

attr_reader :item_name
attr_writer :item_name

end

item = Item.new
puts item.item_name = "TV"

Le code ci-dessous est une réitération de l'exemple d'initialisation ci-dessus où nous utilisons initialize pour définir la valeur des objets de item_name lors de la création.

class Item

attr_reader :item_name

  def initialize(item_name)
    @item_name = item_name
  end

end

item = Item.new("TV")
puts item.item_name

attr_accessor: Effectue les fonctions de attr_reader et attr_writer, en vous sauvant une ligne de code supplémentaire.





ruby switch-statement conditional