Ricerca…


Osservazioni

Gli operatori sono metodi

La maggior parte degli operatori sono in realtà solo metodi, quindi x + y sta chiamando il metodo + di x con l'argomento y , che dovrebbe essere scritto x.+(y) . Se scrivi un tuo metodo che ha il significato semantico di un determinato operatore, puoi implementare la tua variante nella classe.

Come un esempio sciocco:

# 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

Quando usare && vs. and , || contro or

Nota che ci sono due modi per esprimere i booleani, sia && o and , che || oppure or - sono spesso intercambiabili, ma non sempre. Ci riferiremo a queste come varianti di "carattere" e "parola".

Le varianti dei caratteri hanno una precedenza più alta, quindi riducono la necessità di parentesi in istruzioni più complesse per evitare errori imprevisti.

Le varianti di parole erano originariamente intese come operatori di flusso di controllo piuttosto che operatori booleani. Cioè, sono stati progettati per essere utilizzati in dichiarazioni di metodo concatenate:

raise 'an error' and return

Mentre possono essere usati come operatori booleani, la loro precedenza inferiore li rende imprevedibili.

In secondo luogo, molti rubyisti preferiscono la variante del carattere quando creano un'espressione booleana (una che x.nil? || x.empty? true o false ) come x.nil? || x.empty? . D'altra parte, le varianti di parole sono preferite nei casi in cui una serie di metodi sono in fase di valutazione e uno può fallire. Ad esempio, un idioma comune che utilizza la variante di parola per metodi che restituiscono nil in caso di errore potrebbe essere simile a:

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

Precedenza e metodi dell'operatore

Dal più alto al più basso, questa è la tabella di precedenza per Ruby. Le operazioni con precedenza elevata avvengono prima delle operazioni a bassa precedenza.

╔═══════════════════════╦════════════════════════════════════════╦═════════╗
║ 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                      ║         ║
╚═══════════════════════╩════════════════════════════════════════╩═════════╝

Unario + e unario - sono per +obj , -obj o -(some_expression) .

Modificatore-se, modificatore-a meno, ecc. Sono per le versioni modificatore di quelle parole chiave. Ad esempio, questa è una modifica, a meno di un'espressione:

a += 1 unless a.zero?

Gli operatori con ✓ possono essere definiti come metodi. La maggior parte dei metodi sono denominati esattamente come viene chiamato l'operatore, ad esempio:

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"

¹ I metodi Bracket Lookup e Bracket Set ( [] e []= ) hanno i loro argomenti definiti dopo il nome, ad esempio:

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"

² Gli operatori "unary plus" e "unary-minus" sono definiti come metodi denominati +@ e -@ , ad esempio

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

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

³ Nelle prime versioni di Ruby l'operatore di disuguaglianza != E l'operatore non corrispondente !~ Non può essere definito come metodo. Invece, è stato invocato il metodo per l'operatore di uguaglianza corrispondente == o l'operatore di corrispondenza =~ , e il risultato di tale metodo era booleano invertito da Ruby.

Se non definisci i tuoi operatori != O !~ comportamento sopra riportato è ancora vero. Tuttavia, a partire da Ruby 1.9.1, questi due operatori possono anche essere definiti come metodi:

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"

Operatore di uguaglianza dei casi (===)

Conosciuto anche come triple equals .

Questo operatore non verifica l'uguaglianza, ma verifica se l'operando di destra ha una relazione IS A con l'operando di sinistra. In quanto tale, il famoso operatore di uguaglianza dei casi nome è fuorviante.

Questo SO risposta descrive così: il modo migliore per descrivere a === b è "se ho un cassetto etichettato a , ha senso mettere b in esso?" In altre parole, l'insieme a include il membro b ?

Esempi ( fonte )

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

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

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

Classi che === override ===

Molte classi === override === per fornire semantica significativa nelle istruzioni caso. Alcuni di loro sono:

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

Pratica raccomandata

L'uso esplicito dell'operatore di uguaglianza dei casi === dovrebbe essere evitato. Non mette alla prova l'uguaglianza, ma piuttosto la sussunzione , e il suo uso può essere fonte di confusione. Il codice è più chiaro e più facile da capire quando viene utilizzato il metodo del sinonimo.

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

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

Operatore di navigazione sicura

Ruby 2.3.0 ha aggiunto l' operatore di navigazione sicura , &. . Questo operatore ha lo scopo di ridurre il paradigma object && object.property && object.property.method nelle istruzioni condizionali.

Ad esempio, si dispone di un oggetto House con una proprietà address e si desidera trovare lo street_name address . Per programmare questo in modo sicuro per evitare errori nil nelle vecchie versioni di Ruby, dovresti usare un codice come questo:

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

L'operatore di navigazione sicura accorcia questa condizione. Invece, puoi scrivere:

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

Attenzione:
L'operatore di navigazione sicura non ha esattamente lo stesso comportamento del condizionale concatenato. Usando il condizionale concatenato (primo esempio), il blocco if non verrebbe eseguito se, ad esempio, l' address fosse false . L'operatore di navigazione sicura riconosce solo i valori nil , ma consente valori come false . Se l' address è false , l'utilizzo di SNO genera un errore:

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


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow