Поиск…


замечания

Операторы - это методы

Большинство операторов на самом деле являются просто методами, поэтому x + y вызывает метод + x с аргументом y , который был бы записан x.+(y) . Если вы пишете собственный метод, имеющий семантический смысл данного оператора, вы можете реализовать свой вариант в классе.

Как глупый пример:

# 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

Когда использовать && vs. and , || против or

Обратите внимание, что существует два способа выражения булевых: либо && либо and , и || или or - они часто взаимозаменяемы, но не всегда. Мы будем называть их вариантами «характер» и «слово».

Варианты символов имеют более высокий приоритет, поэтому уменьшают потребность в круглых скобках в более сложных выражениях, чтобы избежать неожиданных ошибок.

Варианты слов первоначально были предназначены как операторы потока управления, а не логические операторы. То есть они были предназначены для использования в цепочках:

raise 'an error' and return

Хотя их можно использовать в качестве логических операторов, их более низкий приоритет делает их непредсказуемыми.

Во-вторых, многие рубисты предпочитают вариант символа при создании логического выражения (которое оценивается как true или false ), например x.nil? || x.empty? , С другой стороны, варианты слов предпочтительны в тех случаях, когда оценивается серия методов , и один может потерпеть неудачу. Например, общая идиома, использующая вариант слова для методов, возвращающих nil при отказе, может выглядеть так:

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

Приоритет и методы работы оператора

От самого высокого до самого низкого, это таблица приоритетов для Ruby. Операции с высоким приоритетом происходят до операций с низким приоритетом.

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

Унарные + и унарные - для +obj , -obj или -(some_expression) .

Модификатор-if, модификатор-за исключением и т. Д. Для модификаций версий этих ключевых слов. Например, это модификатор, если только выражение:

a += 1 unless a.zero?

Операторы с ✓ могут быть определены как методы. Большинство методов называются точно так же, как и оператор, например:

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"

¹ Методы поиска скобок и скобки ( [] и []= ) имеют свои аргументы, определенные после имени, например:

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"

² Операторы «унарный плюс» и «унарный минус» определяются как методы с именем +@ и -@ , например

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

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

³ В ранних версиях Ruby оператор неравенства != И несогласованный оператор !~ могли быть определены как методы. Вместо этого был вызван метод для соответствующего оператора равенства == или match operator =~ , и результат этого метода был булевым, инвертированным Ruby.

Если вы не определяете своих собственных != Или !~ Операторов, это поведение по-прежнему остается верным. Однако, с Ruby 1.9.1, эти два оператора также могут быть определены как методы:

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"

Оператор равенства случаев (===)

Также известен как тройной равный .

Этот оператор не проверяет равенство, а проверяет, имеет ли правый операнд связь IS A с левым операндом. Таким образом, популярный оператор равенства имен случаев вводит в заблуждение.

Этот SO-ответ описывает это так: лучший способ описать a === b - «если у меня есть ящик с меткой a , имеет ли смысл вставить b в него?» Другими словами, содержит ли множество a элемент b ?

Примеры ( источник )

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

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

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

Классы, которые переопределяют ===

Многие классы переопределяют === для обеспечения значимой семантики в операторах case. Некоторые из них:

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

Рекомендуемая практика

Следует избегать явного использования оператора равенства случая === . Он не проверяет равенство, а скорее подталкивает , и его использование может ввести в заблуждение. Код проще и понятнее, если вместо этого используется синоним.

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

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

Оператор безопасной навигации

Ruby 2.3.0 добавила безопасного навигатора , &. , Этот оператор предназначен для сокращения парадигмы object && object.property && object.property.method в условных операторах.

Например, у вас есть объект House с свойством address , и вы хотите найти street_name с address . Чтобы запрограммировать это безопасно, чтобы избежать ошибок nil в старых версиях Ruby, вы должны использовать код примерно так:

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

Оператор безопасной навигации сокращает это условие. Вместо этого вы можете написать:

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

Внимание:
Оператор безопасной навигации не имеет точно такого же поведения, как условное условие. Используя условный условный (первый пример), блок if не будет выполнен, если, например, address был false . Оператор безопасной навигации распознает только значения nil , но допускает такие значения, как false . Если address false , использование SNO приведет к ошибке:

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


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow