Ruby Language
Los operadores
Buscar..
Observaciones
Los operadores son métodos
La mayoría de los operadores son en realidad solo métodos, por lo que x + y
está llamando al método +
de x
con el argumento y
, que se escribiría x.+(y)
. Si escribe un método propio que tenga un significado semántico de un operador determinado, puede implementar su variante en la clase.
Como un ejemplo tonto:
# A class that lets you operate on numbers by name.
class NamedInteger
name_to_value = { 'one' => 1, 'two' => 2, ... }
# define the plus method
def + (left_addend, right_addend)
name_to_value(left_addend) + name_to_value(right_addend)
end
...
end
Cuándo usar &&
vs. and
, ||
vs. or
Tenga en cuenta que hay dos formas de expresar valores booleanos, ya sea &&
o and
, y ||
o or
- a menudo son intercambiables, pero no siempre. Nos referiremos a ellos como variantes de "carácter" y "palabra".
Las variantes de caracteres tienen mayor prioridad, por lo que reducir la necesidad de paréntesis en declaraciones más complejas ayuda a evitar errores inesperados.
Las variantes de la palabra originalmente fueron pensadas como operadores de flujo de control en lugar de operadores booleanos. Es decir, fueron diseñados para ser utilizados en declaraciones de métodos encadenados:
raise 'an error' and return
Si bien pueden utilizarse como operadores booleanos, su menor prioridad los hace impredecibles.
En segundo lugar, muchos rubyists prefieren la variante de caracteres cuando crean una expresión booleana (una que se evalúa como true
o false
) como x.nil? || x.empty?
. Por otro lado, las variantes de la palabra se prefieren en los casos en que se evalúan una serie de métodos , y uno puede fallar. Por ejemplo, una expresión idiomática común que usa la variante de la palabra para los métodos que devuelven nil
en caso de falla podría ser:
def deliver_email
# If the first fails, try the backup, and if that works, all good
deliver_by_primary or deliver_by_backup and return
# error handling code
end
Precedencia y métodos del operador
De mayor a menor, esta es la tabla de precedencia para Ruby. Las operaciones de alta precedencia suceden antes de las operaciones de baja precedencia.
╔═══════════════════════╦════════════════════════════════════════╦═════════╗
║ Operators ║ Operations ║ Method? ║
╠═══════════════════════╬════════════════════════════════════════╬═════════╣
║ . ║ Method call (e.g. foo.bar) ║ ║
║ [] []= ║ Bracket Lookup, Bracket Set ║ ✓¹ ║
║ ! ~ + ║ Boolean NOT, complement, unary plus ║ ✓² ║
║ ** ║ Exponentiation ║ ✓ ║
║ - ║ Unary minus ║ ✓² ║
║ * / % ║ Multiplication, division, modulo ║ ✓ ║
║ + - ║ Addition, subtraction ║ ✓ ║
║ << >> ║ Bitwise shift ║ ✓ ║
║ & ║ Bitwise AND ║ ✓ ║
║ | ^ ║ Bitwise OR, Bitwise XOR ║ ✓ ║
║ < <= >= > ║ Comparison ║ ✓ ║
║ <=> == != === =~ !~ ║ Equality, pattern matching, comparison ║ ✓³ ║
║ && ║ Boolean AND ║ ║
║ || ║ Boolean OR ║ ║
║ .. ... ║ Inclusive range, Exclusive range ║ ║
║ ? : ║ Ternary operator ║ ║
║ rescue ║ Modifier rescue ║ ║
║ = += -= ║ Assignments ║ ║
║ defined? ║ Defined operator ║ ║
║ not ║ Boolean NOT ║ ║
║ or and ║ Boolean OR, Boolean AND ║ ║
║ if unless while until ║ Modifier if, unless, while, until ║ ║
║ { } ║ Block with braces ║ ║
║ do end ║ Block with do end ║ ║
╚═══════════════════════╩════════════════════════════════════════╩═════════╝
Unary + y unary - son para +obj
, -obj
o -(some_expression)
.
Modificador-si, modificador-a menos, etc. son para las versiones modificadoras de esas palabras clave. Por ejemplo, esta es una expresión de modificador, a menos que:
a += 1 unless a.zero?
Los operadores con ✓ pueden definirse como métodos. La mayoría de los métodos se nombran exactamente como se nombra al operador, por ejemplo:
class Foo
def **(x)
puts "Raising to the power of #{x}"
end
def <<(y)
puts "Shifting left by #{y}"
end
def !
puts "Boolean negation"
end
end
Foo.new ** 2 #=> "Raising to the power of 2"
Foo.new << 3 #=> "Shifting left by 3"
!Foo.new #=> "Boolean negation"
¹ Los métodos de Búsqueda de corchetes y Conjunto de corchetes ( []
y []=
) tienen sus argumentos definidos después del nombre, por ejemplo:
class Foo
def [](x)
puts "Looking up item #{x}"
end
def []=(x,y)
puts "Setting item #{x} to #{y}"
end
end
f = Foo.new
f[:cats] = 42 #=> "Setting item cats to 42"
f[17] #=> "Looking up item 17"
² Los operadores "unary plus" y "unary minus" se definen como métodos denominados +@
y -@
, por ejemplo
class Foo
def -@
puts "unary minus"
end
def +@
puts "unary plus"
end
end
f = Foo.new
+f #=> "unary plus"
-f #=> "unary minus"
³ En las primeras versiones de Ruby, el operador de desigualdad !=
Y el operador no coincidente !~
No se podían definir como métodos. En su lugar, se invocó el método para el operador de igualdad correspondiente ==
o el operador coincidente =~
, y el resultado de ese método fue booleano invertido por Ruby.
Si no define sus propios operadores !=
O !~
, El comportamiento anterior sigue siendo cierto. Sin embargo, a partir de Ruby 1.9.1, esos dos operadores también pueden definirse como métodos:
class Foo
def ==(x)
puts "checking for EQUALITY with #{x}, returning false"
false
end
end
f = Foo.new
x = (f == 42) #=> "checking for EQUALITY with 42, returning false"
puts x #=> "false"
x = (f != 42) #=> "checking for EQUALITY with 42, returning false"
puts x #=> "true"
class Foo
def !=(x)
puts "Checking for INequality with #{x}"
end
end
f != 42 #=> "checking for INequality with 42"
Operador de igualdad de casos (===)
También conocido como triple igual .
Este operador no prueba la igualdad, sino que prueba si el operando derecho tiene una relación IS A con el operando izquierdo. Como tal, el nombre popular operador de igualdad de casos es engañoso.
Esta respuesta SO lo describe así: la mejor manera de describir a === b
es "si tengo un cajón con la etiqueta a
, ¿tiene sentido poner b
en él?" En otras palabras, ¿el conjunto a
incluye al miembro b
?
Ejemplos ( fuente )
(1..5) === 3 # => true
(1..5) === 6 # => false
Integer === 42 # => true
Integer === 'fourtytwo' # => false
/ell/ === 'Hello' # => true
/ell/ === 'Foobar' # => false
Clases que anulan ===
Muchas clases anulan ===
para proporcionar semántica significativa en las declaraciones de casos. Algunos de ellos son:
╔═════════════════╦════════════════════╗
║ Class ║ Synonym for ║
╠═════════════════╬════════════════════╣
║ Array ║ == ║
║ ║ ║
║ Date ║ == ║
║ ║ ║
║ Module ║ is_a? ║
║ ║ ║
║ Object ║ == ║
║ ║ ║
║ Range ║ include? ║
║ ║ ║
║ Regexp ║ =~ ║
║ ║ ║
║ String ║ == ║
╚═════════════════╩════════════════════╝
Práctica recomendada
Se debe evitar el uso explícito del operador de igualdad de casos ===
. No prueba la igualdad sino la subsunción , y su uso puede ser confuso. El código es más claro y más fácil de entender cuando se utiliza el método de sinónimos en su lugar.
# Bad
Integer === 42
(1..5) === 3
/ell/ === 'Hello'
# Good, uses synonym method
42.is_a?(Integer)
(1..5).include?(3)
/ell/ =~ 'Hello'
Operador de navegación segura
Ruby 2.3.0 agregó el operador de navegación segura , &.
. Este operador está destinado a acortar el paradigma de object && object.property && object.property.method
en sentencias condicionales.
Por ejemplo, tiene un objeto House
con una propiedad de address
y desea buscar el street_name
la street_name
en la address
. Para programar esto de manera segura para evitar errores nulos en versiones anteriores de Ruby, usarías un código como este:
if house && house.address && house.address.street_name
house.address.street_name
end
El operador de navegación segura acorta esta condición. En su lugar, puede escribir:
if house&.address&.street_name
house.address.street_name
end
Precaución:
El operador de navegación segura no tiene exactamente el mismo comportamiento que el condicional encadenado. Usando el condicional encadenado (primer ejemplo), el bloque if
no se ejecutaría si, por ejemplo, la address
fuera false
. El operador de navegación segura solo reconoce valores nil
, pero permite valores como false
. Si la address
es false
, el uso del SNO producirá un error:
house&.address&.street_name
# => undefined method `address' for false:FalseClass