Szukaj…


Uwagi

Operatory to metody

Większość operatorów to tak naprawdę tylko metody, więc x + y wywołuje metodę + x z argumentem y , który zapisano by x.+(y) . Jeśli napiszesz własną metodę mającą znaczenie semantyczne danego operatora, możesz zaimplementować swój wariant w klasie.

Jako głupi przykład:

# 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

Kiedy stosować && vs. and , || vs. or

Zauważ, że istnieją dwa sposoby wyrażania wartości logicznych: && lub and oraz || lub or - często są wymienne, ale nie zawsze. Będziemy nazywać je wariantami „znakowymi” i „słownymi”.

Warianty znaków mają wyższy priorytet, więc zmniejszenie potrzeby stosowania nawiasów w bardziej złożonych instrukcjach pomaga uniknąć nieoczekiwanych błędów.

Warianty słów pierwotnie miały być operatorem przepływu sterowania, a nie operatorem logicznym. Oznacza to, że zostały zaprojektowane do użycia w łańcuchowych instrukcjach metod:

raise 'an error' and return

Chociaż mogą być używane jako operatory logiczne, ich niższy priorytet sprawia, że są nieprzewidywalne.

Po drugie, wielu rubyistów preferuje wariant znaków podczas tworzenia wyrażenia boolowskiego (takiego, który ocenia na true lub false ), takiego jak x.nil? || x.empty? . Z drugiej strony, warianty słów są preferowane w przypadkach, w których analizuje się szereg metod i jedna z nich może zawieść. Na przykład wspólny idiom używający wariantu słowa dla metod zwracających nil w przypadku niepowodzenia może wyglądać następująco:

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

Priorytet operatora i metody

Od najwyższej do najniższej jest to tabela pierwszeństwa dla Ruby. Operacje o wysokim priorytecie mają miejsce przed operacjami o niskim priorytecie.

╔═══════════════════════╦════════════════════════════════════════╦═════════╗
║ 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 + i unary - są dla +obj , -obj lub -(some_expression) .

Modyfikator-jeśli, modyfikator-chyba, itp. Dotyczą wersji modyfikujących tych słów kluczowych. Na przykład jest to modyfikator, chyba że wyrażenie:

a += 1 unless a.zero?

Operatory z ✓ mogą być zdefiniowane jako metody. Większość metod jest nazywana dokładnie tak, jak nazwa operatora, na przykład:

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"

¹ W metodach wyszukiwania wspornika i zestawu wsporników ( [] i []= ) zdefiniowano argumenty po nazwie, na przykład:

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"

² Operatory „unary plus” i „unary minus” są zdefiniowane na przykład jako metody o nazwach +@ i -@

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

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

³ We wczesnych wersjach Ruby operator nierówności != I operator niepasujący !~ Nie mogły być zdefiniowane jako metody. Zamiast tego została wywołana metoda odpowiedniego operatora równości == lub operatora dopasowywania =~ , a wynik tej metody został odwrócony przez wartość logiczną Ruby.

Jeśli nie zdefiniujesz własnych operatorów != Lub !~ , Powyższe zachowanie jest nadal prawdziwe. Jednak od wersji Ruby 1.9.1 te dwa operatory można również zdefiniować jako metody:

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"

Operator równości wielkości liter (===)

Znany również jako potrójny równa się .

Ten operator nie testuje równości, a raczej sprawdza, czy prawy operand ma relację IS A z lewym operandem. W związku z tym popularny operator równości nazw jest mylący.

Ta odpowiedź SO opisuje to w ten sposób: najlepszym sposobem na opisanie a === b jest „jeśli mam szufladę oznaczoną a , czy ma sens umieszczenie w niej b ?”. Innymi słowy, czy zestaw a obejmuje element b ?

Przykłady ( źródło )

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

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

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

Klasy, które zastępują ===

Wiele klas zastępuje === aby zapewnić znaczącą semantykę w instrukcjach case. Niektórzy z nich są:

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

Zalecana praktyka

Należy unikać jawnego użycia operatora równości wielkości === . Nie testuje równości, ale raczej subsumpcję , a jej użycie może być mylące. Kod jest jaśniejszy i łatwiejszy do zrozumienia, gdy zamiast niego używana jest metoda synonimiczna.

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

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

Operator bezpiecznej nawigacji

Ruby 2.3.0 dodał bezpieczny operator nawigacji , &. . Ten operator ma na celu skrócenie paradygmatu object && object.property && object.property.method w instrukcjach warunkowych.

Na przykład masz obiekt House z właściwością address i chcesz znaleźć nazwę street_name na podstawie address . Aby bezpiecznie to zaprogramować, aby uniknąć błędów zero w starszych wersjach Rubiego, użyj kodu takiego jak ten:

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

Operator bezpiecznej nawigacji skraca ten warunek. Zamiast tego możesz napisać:

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

Uwaga:
Operator bezpiecznej nawigacji nie zachowuje się dokładnie tak samo jak łańcuch warunkowy. Korzystając z warunkowego łańcucha (pierwszy przykład), blok if nie zostałby wykonany, jeśli powiedzmy, że address był false . Operator bezpiecznej nawigacji rozpoznaje tylko wartości nil , ale dopuszcza takie wartości, jak false . Jeśli address jest false , użycie SNO spowoduje błąd:

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


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow