Sök…


Anmärkningar

Operatörer är metoder

De flesta operatörer är faktiskt bara metoder, så x + y kallar + -metoden för x med argumentet y , vilket skulle skrivas x.+(y) . Om du skriver en egen metod som har semantisk betydelse av en given operatör kan du implementera din variant i klassen.

Som ett dumt exempel:

# 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

När && vs. and , || mot or

Observera att det finns två sätt att uttrycka booleaner, antingen && eller and , och || eller or - de är ofta utbytbara, men inte alltid. Vi kommer att hänvisa till dessa som "karaktär" och "ord" varianter.

Karaktärvarianterna har högre prioritet så minska behovet av parenteser i mer komplexa påståenden hjälper till att undvika oväntade fel.

Ordet varianter var ursprungligen avsedda som kontrollflödesoperatörer snarare än booleska operatörer. Det vill säga de var designade för att användas i uttalade metoduttalanden:

raise 'an error' and return

Medan de kan användas som booleska operatörer, gör deras lägre prioritet dem oförutsägbara.

För det andra föredrar många rubinister karaktärvarianten när de skapar ett booleskt uttryck (ett som utvärderar till true eller false ) som x.nil? || x.empty? . Å andra sidan föredras ordvarianter i fall där en serie metoder utvärderas och en kan misslyckas. Till exempel kan en vanlig formspråk som använder ordvarianten för metoder som returnerar nil vid misslyckande se ut:

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

Operatörens prioritet och metoder

Från högsta till lägsta är detta föregångstabellen för Ruby. Operationer med hög prioritet inträffar före operationer med låg prioritet.

╔═══════════════════════╦════════════════════════════════════════╦═════════╗
║ 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 + och unary - är för +obj , -obj eller -(some_expression) .

Modifier-if, modifier-ONLY, etc. är för modifieringsversionerna av dessa nyckelord. Till exempel är detta en modifierare om inte uttrycket:

a += 1 unless a.zero?

Operatörer med ✓ kan definieras som metoder. De flesta metoder heter exakt som operatören heter, till exempel:

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"

Methods Metoderna Bracket Lookup and Bracket Set ( [] och []= ) har sina argument definierade efter namnet, till exempel:

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"

² Operatörerna "unary plus" och "unary minus" definieras som metoder med namnet +@ och -@ , till exempel

class Foo
  def -@
    puts "unary minus"
  end
  def +@
    puts "unary plus"
  end
end

f = Foo.new
+f               #=> "unary plus"
-f               #=> "unary minus"

³ I tidiga versioner av Ruby kunde ojämlikhetsoperatören != Och den icke-matchande operatören !~ Inte definieras som metoder. Istället åberopades metoden för motsvarande jämställdhetsoperatör == eller matchande operatör =~ , och resultatet av den metoden boolesiska inverterades av Ruby.

Om du inte definierar dina egna != Eller !~ Operatörer är ovanstående beteende fortfarande sant. Från Ruby 1.9.1 kan emellertid dessa två operatörer också definieras som metoder:

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"

Ärende jämställdhetsoperatör (===)

Även känd som trippel lika .

Denna operatör testar inte jämställdhet, utan testar snarare om den högra operanden har en IS A-relation med den vänstra operanden. Som sådan är den populära namnet likabehandlingsoperatören vilseledande.

Detta SO-svar beskriver det så: det bästa sättet att beskriva a === b är "om jag har en låda märkt a , är det meningsfullt att lägga b i den?" Med andra ord inkluderar uppsättningen a medlemmen b ?

Exempel ( källa )

(1..5) === 3            # => true
(1..5) === 6            # => false

Integer === 42          # => true
Integer === 'fourtytwo' # => false

/ell/ === 'Hello'       # => true
/ell/ === 'Foobar'      # => false

Klasser som åsidosätter ===

Många klasser åsidosätter === att tillhandahålla meningsfull semantik i uttalanden. Några av dem är:

╔═════════════════╦════════════════════╗
║      Class      ║     Synonym for    ║
╠═════════════════╬════════════════════╣
║ Array           ║ ==                 ║
║                 ║                    ║
║ Date            ║ ==                 ║
║                 ║                    ║
║ Module          ║ is_a?              ║
║                 ║                    ║
║ Object          ║ ==                 ║
║                 ║                    ║
║ Range           ║ include?           ║
║                 ║                    ║
║ Regexp          ║ =~                 ║
║                 ║                    ║
║ String          ║ ==                 ║
╚═════════════════╩════════════════════╝

Rekommenderad praxis

Explicit användning av operatören om jämställdhet === bör undvikas. Det testar inte jämställdhet utan snarare subumption , och dess användning kan vara förvirrande. Koden är tydligare och lättare att förstå när synonymmetoden används istället.

# Bad
Integer === 42
(1..5) === 3
/ell/ === 'Hello'

# Good, uses synonym method
42.is_a?(Integer)
(1..5).include?(3)
/ell/ =~ 'Hello'

Safe Navigation Operator

Ruby 2.3.0 lade till den säkra navigeringsoperatören &. . Den här operatören är avsedd att förkorta paradigmet för object && object.property && object.property.method i villkorade uttalanden.

Till exempel, har du House objekt med en address egendom, och du vill hitta street_name från address . För att programmera detta på ett säkert sätt för att undvika noll-fel i äldre Ruby-versioner, skulle du använda kod något liknande:

if house && house.address && house.address.street_name
  house.address.street_name
end

Den säkra navigeringsoperatören förkortar detta villkor. Istället kan du skriva:

if house&.address&.street_name
  house.address.street_name
end

Varning:
Den säkra navigeringsoperatören har inte exakt samma beteende som den kedjade villkoren. Med hjälp av den kedjade villkorade (första exemplet), if blocket inte skulle köras om, säg address var false . Den säkra navigeringsoperatören känner bara till nil , men tillåter värden som false . Om address är false , använder SNO ett fel:

house&.address&.street_name
# => undefined method `address' for false:FalseClass


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow