Ruby Language
операторы
Поиск…
замечания
Операторы - это методы
Большинство операторов на самом деле являются просто методами, поэтому 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