Ruby Language
operators
Zoeken…
Opmerkingen
Operators zijn methoden
De meeste operatoren zijn eigenlijk alleen methoden, dus x + y
roept de +
-methode van x
met argument y
, dat zou worden geschreven x.+(y)
. Als u een eigen methode schrijft met een semantische betekenis van een bepaalde operator, kunt u uw variant in de klas implementeren.
Als een gek voorbeeld:
# 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
Wanneer &&
vs. and
, ||
vs. or
Merk op dat er twee manieren zijn om Booleans uit te drukken, ofwel &&
of and
, en ||
of or
- ze zijn vaak uitwisselbaar, maar niet altijd. We zullen deze varianten "karakter" en "woord" noemen.
De karaktervarianten hebben een hogere prioriteit, dus het verminderen van de behoefte aan haakjes in complexere beweringen helpt onverwachte fouten te voorkomen.
De woordvarianten waren oorspronkelijk bedoeld als bedieningsstroomoperatoren in plaats van booleaanse operatoren. Dat wil zeggen, ze zijn ontworpen om te worden gebruikt in verklaringen met een kettingmethode:
raise 'an error' and return
Hoewel ze kunnen worden gebruikt als booleaanse operatoren, maakt hun lagere prioriteit ze onvoorspelbaar.
Ten tweede geven veel rubyisten de voorkeur aan de karaktervariant bij het maken van een booleaanse uitdrukking (een die true
of false
) zoals x.nil? || x.empty?
. Aan de andere kant hebben de woordvarianten de voorkeur in gevallen waarin een reeks methoden wordt geëvalueerd en één kan falen. Een veelvoorkomend idioom dat de woordvariant gebruikt voor methoden die nil
bij een fout retourneren, kan er bijvoorbeeld uitzien als:
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
Prioriteit van de operator en methoden
Van hoogste naar laagste, dit is de prioriteitstabel voor Ruby. Operaties met hoge prioriteit vinden plaats vóór operaties met lage prioriteit.
╔═══════════════════════╦════════════════════════════════════════╦═════════╗
║ 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 + en unary - zijn voor +obj
, -obj
of -(some_expression)
.
Modifier-if, modifier-tenzij, etc. zijn voor de modificatieversies van die zoekwoorden. Dit is bijvoorbeeld een modifier-tenzij expressie:
a += 1 unless a.zero?
Operators met een ✓ kunnen worden gedefinieerd als methoden. De meeste methoden worden precies zo genoemd als de operator, bijvoorbeeld:
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"
¹ De Bracket-lookup en Bracket Set-methoden ( []
en []=
) hebben hun argumenten gedefinieerd achter de naam, bijvoorbeeld:
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"
² De operatoren "unary plus" en "unary minus" worden gedefinieerd als methoden met de naam +@
en -@
, bijvoorbeeld
class Foo
def -@
puts "unary minus"
end
def +@
puts "unary plus"
end
end
f = Foo.new
+f #=> "unary plus"
-f #=> "unary minus"
³ In vroege versies van Ruby konden de operator voor ongelijkheid !=
En de operator die niet overeenkomt !~
Niet als methoden worden gedefinieerd. In plaats daarvan werd de methode voor de overeenkomstige gelijkheidsoperator ==
of matching operator =~
aangeroepen, en het resultaat van die methode werd boolean omgekeerd door Ruby.
Als u uw eigen !=
Of !~
-Operators niet definieert, is het bovenstaande gedrag nog steeds waar. Vanaf Ruby 1.9.1 kunnen deze twee operatoren echter ook als methoden worden gedefinieerd:
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"
Case-gelijkheid operator (===)
Ook bekend als triple is gelijk aan .
Deze operator test geen gelijkheid, maar test eerder of de rechteroperand een IS A-relatie heeft met de linkeroperand. Als zodanig is de populaire operator voor gelijkheid van naamgevallen misleidend.
Dit ZO antwoord beschrijft het als volgt: de beste manier om a === b
te beschrijven is "als ik een lade heb met het label a
, is het dan logisch om b
erin te plaatsen?" Met andere woorden, omvat de set a
het lid b
?
Voorbeelden ( bron )
(1..5) === 3 # => true
(1..5) === 6 # => false
Integer === 42 # => true
Integer === 'fourtytwo' # => false
/ell/ === 'Hello' # => true
/ell/ === 'Foobar' # => false
Klassen die negeren ===
Veel klassen negeren ===
om betekenisvolle semantiek te bieden in case-statements. Sommige ervan zijn:
╔═════════════════╦════════════════════╗
║ Class ║ Synonym for ║
╠═════════════════╬════════════════════╣
║ Array ║ == ║
║ ║ ║
║ Date ║ == ║
║ ║ ║
║ Module ║ is_a? ║
║ ║ ║
║ Object ║ == ║
║ ║ ║
║ Range ║ include? ║
║ ║ ║
║ Regexp ║ =~ ║
║ ║ ║
║ String ║ == ║
╚═════════════════╩════════════════════╝
Aanbevolen oefening
Expliciet gebruik van de case-equity-operator ===
moet worden vermeden. Het test geen gelijkheid maar eerder subsumptie , en het gebruik ervan kan verwarrend zijn. Code is duidelijker en gemakkelijker te begrijpen wanneer in plaats daarvan de synoniemenmethode wordt gebruikt.
# Bad
Integer === 42
(1..5) === 3
/ell/ === 'Hello'
# Good, uses synonym method
42.is_a?(Integer)
(1..5).include?(3)
/ell/ =~ 'Hello'
Veilige navigatie-operator
Ruby 2.3.0 heeft de veilige navigatie-operator toegevoegd , &.
. Deze operator is bedoeld om het paradigma van object && object.property && object.property.method
in voorwaardelijke verklaringen in te korten.
U hebt bijvoorbeeld een House
object met de eigenschap address
en u wilt de street_name
van het address
. Om dit veilig te programmeren om nulfouten in oudere Ruby-versies te voorkomen, gebruikt u code zoiets als dit:
if house && house.address && house.address.street_name
house.address.street_name
end
De veilige navigatie-operator verkort deze toestand. In plaats daarvan kunt u schrijven:
if house&.address&.street_name
house.address.street_name
end
Voorzichtigheid:
De veilige navigatie-operator heeft niet precies hetzelfde gedrag als de voorwaardelijke keten. Met behulp van de gekoppelde voorwaardelijke (eerste voorbeeld), zou het if
blok niet worden uitgevoerd als, zeg, address
false
. De veilige navigatie-operator herkent alleen nil
, maar staat waarden zoals false
. Als het address
false
, levert het gebruik van SNO een fout op:
house&.address&.street_name
# => undefined method `address' for false:FalseClass