=== vs == en Ruby

En Ruby, quelle est la différence entre == et ===? Le RDoc dit

Egalité de cas – Pour Object de classe, le même que pour appeler # ==, mais généralement remplacé par des descendants pour fournir une sémantique significative dans les instructions de cas.

Est-ce que #== le même que == ? Et pourriez-vous donner un exemple de quand / comment cela est utilisé dans les déclarations de cas?

Les deux n’ont vraiment rien à voir les uns avec les autres. En particulier, #== est l’opérateur d’égalité et #=== n’a absolument rien à voir avec l’égalité. Personnellement, je trouve plutôt regrettable que #=== ressemble tellement à #== , utilise le signe égal et est souvent appelé l’ opérateur d’égalité de casse, l’opérateur sortingple equals ou l’ opérateur sortingple lorsqu’il n’a rien à voir avec l’égalité.

J’appelle #=== l’ opérateur de la subsomption de cas (c’est le mieux que je puisse trouver, je suis ouvert aux suggestions, en particulier celles des anglophones natifs).

La meilleure façon de décrire a === b est “si j’ai un tiroir étiqueté a , est-il judicieux d’y mettre b ?”

Ainsi, par exemple, le Module#=== teste si b.is_a?(a) . Si vous avez un Integer === 2 , est-il judicieux de mettre 2 dans une case intitulée Integer ? Oui. Qu’en est-il Integer === 'hello' ? Évidemment pas.

Un autre exemple est Regexp#=== . Il teste un match. Est-il judicieux de mettre 'hello' dans une case intitulée /el+/ ? Oui.

Pour les collections telles que les plages, la Range#=== est définie comme un test d’appartenance: il est logique de placer un élément dans une zone étiquetée avec une collection si cet élément est dans la collection.

Donc, c’est ce que fait #=== : il teste si l’argument peut être inclus dans le récepteur.

Qu’est-ce que cela doit avec les expressions de case ? Simple:

 case foo when bar baz end 

est le même que

 if bar === foo baz end 

Oui, par #== les documents signifient “la méthode d’instance == de l’object actuel”.

=== est utilisé dans les déclarations de cas en tant que telles:

 case obj when x foo when y bar end 

Est le même que

 if x === obj foo elsif y === obj bar end 

Certaines classes qui définissent leurs propres === sont Range (pour agir comme include? ), Class (pour agir comme obj.is_a?(klass) ) et Regexp (pour agir comme =~ sauf pour renvoyer un booléen). Certaines classes qui ne définissent pas leurs propres === sont les classes numériques et Ssortingng.

Alors

 case x when 0 puts "Lots" when Numeric puts(100.0 / x) when /^\d+$/ puts(100.0 / x.to_f) default raise ArgumentError, "x is not a number or numeric ssortingng" end 

est le même que

 if 0 == x puts "Lots" elsif x.is_a? Numeric puts(100.0 / x) elsif x =~ /^\d+$/ puts(100.0 / x.to_f) else raise ArgumentError, "x is not a number or numeric ssortingng" end 

Fait amusant, === est également utilisé pour faire correspondre les exceptions dans rescue

Voici un exemple

 class Example def self.===(exception) puts "Triple equals has been called." true end end raise rescue Example # => prints "Triple equals has been called." # => no exception raised 

Ceci est utilisé pour correspondre aux erreurs du système.

SystemCallError.=== a été défini pour retourner true lorsque les deux ont le même numéro d’erreur. Avec ce système, les erreurs d’appels avec le même numéro d’erreur, telles que Errno::EAGAIN et Errno::EWOULDBLOCK , peuvent toutes deux être Errno::EWOULDBLOCK listant qu’une.