Estoy tratando de entender la diferencia entre estos cuatro métodos. Sé por defecto que ==
llama al método equal?
que devuelve verdadero cuando ambos operandos se refieren exactamente al mismo objeto.
===
por defecto también llama a ==
qué llamadas equal?
... bueno, entonces, si estos tres métodos no se anulan, entonces supongo
===
, ¿ ==
y equal?
hacer exactamente lo mismo?
Ahora viene eql?
. ¿Qué hace esto (por defecto)? ¿Hace una llamada al hash / id del operando?
¿Por qué Ruby tiene tantos signos de igualdad? ¿Se supone que difieren en semántica?
ruby
comparison
operators
equality
denniss
fuente
fuente
"a" == "a"
,"a" === "a"
y"a".eql? "a"
. Pero esto es falso:"a".equal? "a"
(El mío es rubí 1.9.2-p180)a = Object.new; b = Object.new
entonces todo==
,===
,.equal?
,.eql?
volverátrue
aa
frentea
y falso paraa
vsb
.Respuestas:
Voy a citar fuertemente la documentación de Object aquí, porque creo que tiene algunas explicaciones excelentes. Te animo a que lo leas, y también a la documentación de estos métodos, ya que se anulan en otras clases, como String .
Nota al margen: si desea probarlos en diferentes objetos, use algo como esto:
==
- "igualdad" genéricaEsta es la comparación más común y, por lo tanto, el lugar más fundamental donde usted (como autor de una clase) puede decidir si dos objetos son "iguales" o no.
===
- igualdad de casosEsto es increíblemente útil. Ejemplos de cosas que tienen
===
implementaciones interesantes :Entonces puedes hacer cosas como:
Vea mi respuesta aquí para ver un claro ejemplo de cómo
case
+Regex
puede hacer que el código sea mucho más limpio. Y, por supuesto, al proporcionar su propia===
implementación, puede obtener unacase
semántica personalizada .eql?
-Hash
igualdadPor lo tanto, puede anular esto para sus propios usos, o puede anular
==
y usaralias :eql? :==
para que los dos métodos se comporten de la misma manera.equal?
- comparación de identidadEsta es efectivamente la comparación de punteros.
fuente
Numeric
maneja de una manera más estricta==
. Realmente depende del autor de la clase.===
se usa con poca frecuencia fuera de lascase
declaraciones.===
que significa "coincidencias" (aproximadamente). Como en ", la expresión regular coincide con la cadena" o "el rango coincide (incluye) el número".Me encanta la respuesta de jtbandes, pero como es bastante larga, agregaré mi propia respuesta compacta:
==
,===
,eql?
,equal?
Son 4 comparadores, es decir. 4 formas de comparar 2 objetos, en Ruby.
Como, en Ruby, todos los comparadores (y la mayoría de los operadores) son en realidad llamadas de método, puede cambiar, sobrescribir y definir la semántica de estos métodos de comparación usted mismo. Sin embargo, es importante entender, cuando las construcciones de lenguaje interno de Ruby usan qué comparador:
==
(comparación de valores)Ruby usa: == en todas partes para comparar los valores de 2 objetos, por ejemplo. Valores hash:
===
(comparación de casos)Ruby usa: === en caso / cuando construye. Los siguientes fragmentos de código son lógicamente idénticos:
eql?
(Comparación de clave hash)Ruby usa: eql? (en combinación con el método hash) para comparar Hash-keys. En la mayoría de las clases: ¿eql? es idéntico a: ==.
Conocimiento sobre: eql? solo es importante cuando quieres crear tus propias clases especiales:
Nota: El conjunto Ruby-class de uso común también se basa en la comparación de claves hash.
equal?
(comparación de identidad de objeto)Ruby usa: igual? para verificar si dos objetos son idénticos. Se supone que este método (de la clase BasicObject) no se sobrescribe.
fuente
eql?
es muy engañoso.eql?
es una comparación de igualdad que es consistente con cómo se calcula el hash, es decir, loa.eql?(b)
garantizaa.hash == b.hash
. No , no simplemente comparar los códigos hash.bar === foo
y nofoo === bar
? Espero que esto último sea correcto y es importante ya que el compilador llama al lado izquierdo: === ``bar === foo
: Ruby usa el valor del caso en el lado izquierdo y la variable del caso en el lado derecho. Esto podría tener que ver con evitar NPE (excepciones de puntero nulo).Operadores de igualdad: == y! =
El operador ==, también conocido como igualdad o doble igualdad, devolverá verdadero si ambos objetos son iguales y falso si no lo son.
El operador! =, También conocido como desigualdad, es lo opuesto a ==. Devolverá verdadero si ambos objetos no son iguales y falso si son iguales.
Tenga en cuenta que dos matrices con los mismos elementos en un orden diferente no son iguales, las versiones en mayúsculas y minúsculas de la misma letra no son iguales, etc.
Al comparar números de diferentes tipos (p. Ej., Entero y flotante), si su valor numérico es el mismo, == devolverá verdadero.
¿igual?
A diferencia del operador == que prueba si ambos operandos son iguales, el método igual verifica si los dos operandos se refieren al mismo objeto. Esta es la forma más estricta de igualdad en Ruby.
Ejemplo: a = "zen" b = "zen"
En el ejemplo anterior, tenemos dos cadenas con el mismo valor. Sin embargo, son dos objetos distintos, con diferentes ID de objeto. Por lo tanto, el igual? El método devolverá falso.
Intentemos nuevamente, solo que esta vez b será una referencia a a. Observe que la ID del objeto es la misma para ambas variables, ya que apuntan al mismo objeto.
eql?
En la clase Hash, el eql? método se utiliza para probar claves para la igualdad. Se requieren algunos antecedentes para explicar esto. En el contexto general de la informática, una función hash toma una cadena (o un archivo) de cualquier tamaño y genera una cadena o número entero de tamaño fijo llamado hashcode, comúnmente conocido como solo hash. Algunos tipos de hashcode comúnmente utilizados son MD5, SHA-1 y CRC. Se utilizan en algoritmos de cifrado, indexación de bases de datos, comprobación de integridad de archivos, etc. Algunos lenguajes de programación, como Ruby, proporcionan un tipo de colección llamada tabla hash. Las tablas hash son colecciones tipo diccionario que almacenan datos en pares, que consisten en claves únicas y sus valores correspondientes. Debajo del capó, esas claves se almacenan como códigos hash. Las tablas hash se conocen comúnmente como solo hashes. Observe cómo la palabra hash puede referirse a un código hash o a una tabla hash.
Ruby proporciona un método incorporado llamado hash para generar códigos hash. En el siguiente ejemplo, toma una cadena y devuelve un código hash. Observe cómo las cadenas con el mismo valor siempre tienen el mismo código hash, aunque sean objetos distintos (con diferentes ID de objeto).
El método hash se implementa en el módulo Kernel, incluido en la clase Object, que es la raíz predeterminada de todos los objetos Ruby. Algunas clases como Symbol e Integer usan la implementación predeterminada, otras como String y Hash proporcionan sus propias implementaciones.
En Ruby, cuando almacenamos algo en un hash (colección), el objeto proporcionado como clave (por ejemplo, cadena o símbolo) se convierte y almacena como un código hash. Más tarde, al recuperar un elemento del hash (colección), proporcionamos un objeto como clave, que se convierte en un hashcode y se compara con las claves existentes. Si hay una coincidencia, se devuelve el valor del elemento correspondiente. La comparación se realiza utilizando el eql? método debajo del capó.
En la mayoría de los casos, el eql? El método se comporta de manera similar al método ==. Sin embargo, hay algunas excepciones. Por ejemplo, eql? no realiza conversión de tipo implícito al comparar un entero con un flotante.
Operador de igualdad de casos: ===
Muchas de las clases integradas de Ruby, como String, Range y Regexp, proporcionan sus propias implementaciones del operador ===, también conocido como igualdad de casos, triples iguales o tres iguales. Debido a que se implementa de manera diferente en cada clase, se comportará de manera diferente dependiendo del tipo de objeto al que fue llamado. En general, devuelve verdadero si el objeto de la derecha "pertenece" o "es miembro del" objeto de la izquierda. Por ejemplo, se puede usar para probar si un objeto es una instancia de una clase (o una de sus subclases).
Se puede lograr el mismo resultado con otros métodos que probablemente sean los más adecuados para el trabajo. Por lo general, es mejor escribir código que sea fácil de leer siendo lo más explícito posible, sin sacrificar la eficiencia y la concisión.
Observe que el último ejemplo devuelve falso porque los enteros como 2 son instancias de la clase Fixnum, que es una subclase de la clase Integer. El ===, es_a? e instancia_de? Los métodos devuelven verdadero si el objeto es una instancia de la clase dada o de cualquier subclase. El método instance_of es más estricto y solo devuelve verdadero si el objeto es una instancia de esa clase exacta, no una subclase.
El is_a? y kind_of? Los métodos se implementan en el módulo Kernel, que se mezcla con la clase Object. Ambos son alias del mismo método. Vamos a verificar:
Kernel.instance_method (: kind_of?) == Kernel.instance_method (: is_a?) # Salida: => true
Implementación de rango de ===
Cuando se llama al operador === en un objeto de rango, devuelve verdadero si el valor de la derecha cae dentro del rango de la izquierda.
Recuerde que el operador === invoca el método === del objeto de la izquierda. Entonces (1..4) === 3 es equivalente a (1..4). === 3. En otras palabras, la clase del operando de la izquierda definirá qué implementación del método === será llamado, por lo que las posiciones de los operandos no son intercambiables.
Implementación de expresiones regulares de ===
Devuelve verdadero si la cadena de la derecha coincide con la expresión regular de la izquierda. / zen / === "practica zazen hoy" # Salida: => verdadero # es lo mismo que "practica zazen hoy" = ~ / zen /
Uso implícito del operador === en declaraciones de caso / cuándo
Este operador también se utiliza bajo el capó en las declaraciones de caso / cuándo. Ese es su uso más común.
En el ejemplo anterior, si Ruby hubiera usado implícitamente el operador de doble igualdad (==), el rango 10..20 no se consideraría igual a un número entero como 15. Coinciden porque el operador de triple igualdad (===) es implícitamente utilizado en todas las declaraciones de caso / cuándo. El código en el ejemplo anterior es equivalente a:
Operadores de coincidencia de patrones: = ~ y! ~
Los operadores = ~ (igual-tilde) y! ~ (Bang-tilde) se utilizan para unir cadenas y símbolos con patrones de expresiones regulares.
La implementación del método = ~ en las clases String y Symbol espera una expresión regular (una instancia de la clase Regexp) como argumento.
La implementación en la clase Regexp espera una cadena o un símbolo como argumento.
En todas las implementaciones, cuando la cadena o el símbolo coincide con el patrón Regexp, devuelve un número entero que es la posición (índice) de la coincidencia. Si no hay coincidencia, devuelve nulo. Recuerde que, en Ruby, cualquier valor entero es "verdadero" y nulo es "falso", por lo que el operador = ~ puede usarse en declaraciones if y operadores ternarios.
Los operadores de coincidencia de patrones también son útiles para escribir sentencias if más cortas. Ejemplo:
El operador! ~ Es lo opuesto a = ~, devuelve verdadero cuando no hay coincidencia y falso si hay coincidencia.
Más información está disponible en esta publicación de blog .
fuente
:zen === "zen"
devuelve falsoRuby expone varios métodos diferentes para manejar la igualdad:
Continúe leyendo haciendo clic en el enlace a continuación, me dio una comprensión clara y resumida.
Espero que ayude a los demás.
fuente
=== # --- igualdad de casos
== # --- igualdad genérica
ambos funcionan de manera similar pero "===" incluso hacen declaraciones de casos
aqui la diferencia
fuente
a==b
a continuacióna===b
. Peroa===b
es mucho más poderoso.===
no es simétrico ya===b
significa algo muy diferente deb===a
, y mucho menosa==b
.Me gustaría ampliar el
===
operador.===
no es un operador de igualdad!No.
Vamos a entender ese punto realmente.
Es posible que esté familiarizado
===
como operador de igualdad en Javascript y PHP, pero esto no es un operador de igualdad en Ruby y tiene una semántica fundamentalmente diferente.Entonces, ¿qué hace
===
?===
es el operador de coincidencia de patrones!===
coincide con expresiones regulares===
comprueba membresía de rango===
comprueba ser instancia de una clase===
llama expresiones lambda===
a veces verifica la igualdad, pero en general noEntonces, ¿cómo tiene sentido esta locura?
Enumerable#grep
utiliza===
internamentecase when
declaraciones utilizan===
internamenterescue
utiliza===
internamenteEs por eso que puede usar expresiones regulares y clases y rangos e incluso expresiones lambda en una
case when
declaración.Algunos ejemplos
Todos estos ejemplos también funcionan
pattern === value
con elgrep
método.fuente
Escribí una prueba simple para todo lo anterior.
fuente