147 votes

Types de classes et déclarations de cas en Ruby

Quelle est la différence entre

case item.class
when MyClass
  # do something here
when Array
  # do something different here
when String
  # do a third thing
end

et

case item.class
when MyClass.class
  # do something here
when Array.class
  # do something different here
when String.class
  # do a third thing
end

Pour une raison quelconque, le premier fonctionne parfois et pas le second, et d'autres fois, le second fonctionne et pas le premier. Pourquoi ? Laquelle est la "bonne" façon de procéder ?

2 votes

String est une classe. La classe d'une classe est Class.

1 votes

Notez que MyClass === obj utilise le Module#=== pour vérifier si obj est une instance de MyClass .

254voto

Nakilon Points 11635

Vous devez utiliser :

case item
when MyClass
...

J'ai eu le même problème : Comment attraper la classe Errno::ECONNRESET dans le "cas où" ?

1 votes

Merci ! Désolé de faire double emploi (ou une sorte de double emploi), mais plusieurs recherches n'ont pas permis de trouver la question précédente. Il semble que l'utilisation de === par l'instruction case soit un problème assez courant, maintenant que je vois que c'est le problème. Cela devrait probablement être signalé plus souvent dans les tutoriels et autres (mais je parie que de nombreux auteurs de tutoriels ne sont pas conscients de cela non plus).

4 votes

Une mise en garde qui n'a pas été mentionnée si vous utilisez ActiveRecord. La méthode ActiveRecord === sur les comparaisons de classes utilise .is_a ?, ce qui signifie que les sous-classes d'une classe seront évaluées à true dans l'instruction case. github.com/rails/rails/blob/

67voto

Fred Points 4213

Oui, Nakilon a raison, il faut savoir comment fonctionne l'opérateur === sur l'objet donné dans la section when clause. En Rubis

case item
when MyClass
...
when Array
...
when String
...

est vraiment

if MyClass === item
...
elsif Array === item
...
elsif String === item
...

Comprenez que ce cas est l'appel d'une méthode triqual ( MyClass.===(item) par exemple), et cette méthode peut être définie pour faire ce que vous voulez, et vous pouvez alors utiliser l'instruction case avec précisionw

1 votes

Si j'ai arr = [] puis j'ai remarqué que if Array === arr sera évalué à true mais if arr === Array sera évalué à false. Quelqu'un peut-il m'expliquer ?

5 votes

\=== est juste une méthode qui peut être définie pour faire ce que le concepteur d'une classe veut qu'elle fasse. Rappelez-vous également que a === b signifie en réalité a.=== b, de sorte que si vous intervertissez a et b, vous pouvez obtenir un comportement différent. Il n'y a aucune garantie que === soit commutatif. En fait, Array === Array est faux, mais Object === Object est vrai, donc Array redéfinit la sémantique de ===.

20voto

user664833 Points 4597

Vous pouvez utiliser :

case item.class.to_s
    when 'MyClass'

...lorsque la torsion suivante n'est pas possible :

case item
    when MyClass

La raison en est que case utiliza === y la relation la === L'opérateur décrit est non commutatif . Par exemple, 5 es un Integer mais c'est Integer a 5 ? C'est ainsi que vous devez penser à case / when .

5voto

Ken Bloom Points 27197

En Ruby, un nom de classe est une constante qui fait référence à un objet de type Class qui décrit une classe particulière. Cela signifie que dire MyClass en Ruby est équivalent à dire MyClass.class en Java.

obj.class est un objet de type Class décrivant la classe de obj . Si obj.class es MyClass entonces obj a été créé en utilisant MyClass.new (en gros). MyClass est un objet de type Class qui décrit tout objet créé en utilisant MyClass.new .

MyClass.class est la classe de la MyClass (c'est l'objet classe de l'objet de type Class qui décrit tout objet créé en utilisant MyClass.new ). En d'autres termes, MyClass.class == Class .

1voto

Jack Points 61503

Cela dépend de la nature de votre item variable. S'il s'agit d'une instance d'un objet, par ex.

t = 5

puis

t.class == Fixnum

mais s'il s'agit d'une classe à part entière, par exemple

t = Array

alors ce sera un Class donc

t.class == Class

EDITAR : veuillez vous référer à Comment attraper la classe Errno::ECONNRESET dans le "cas où" ? comme indiqué par Nakilon puisque ma réponse pourrait être fausse.

0 votes

En Ruby, tout est "une instance d'un objet".

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X