Вызов методов
Вызов метода отправляет сообщение объекту, чтобы он мог выполнить некоторую работу.
В Ruby вы отправляете сообщение объекту следующим образом:
my_method()
Обратите внимание, что скобки необязательны:
my_method
За исключением случаев, когда использование скобок отличается от их отсутствия, в этом документе используются скобки при наличии аргументов, чтобы избежать путаницы.
Этот раздел посвящен только вызову методов. Также см. документацию по синтаксису определения методов.
Получатель
self — это получатель по умолчанию. Если вы не укажете получателя, self будет использован. Чтобы указать получателя, используйте .:
my_object.my_method
Это отправляет сообщение my_method получателю my_object. Любой объект может быть получателем, но в зависимости от видимости метода отправка сообщения может вызвать NoMethodError.
Вы также можете использовать :: для обозначения получателя, но это редко используется из-за возможной путаницы с :: для пространств имен.
Оператор безопасной навигации
&., называемый «оператором безопасной навигации», позволяет пропустить вызов метода, когда получатель nil. Он возвращает nil и не вычисляет аргументы метода, если вызов пропущен.
REGEX = /(ruby) is (\w+)/i "Ruby is awesome!".match(REGEX).values_at(1, 2) # => ["Ruby", "awesome"] "Python is fascinating!".match(REGEX).values_at(1, 2) # NoMethodError: undefined method `values_at' for nil:NilClass "Python is fascinating!".match(REGEX)&.values_at(1, 2) # => nil
Это позволяет легко объединять методы, которые могут возвращать пустое значение. Обратите внимание, что &. пропускает только один следующий вызов, поэтому для более длинной цепочки необходимо добавить оператор на каждом уровне:
"Python is fascinating!".match(REGEX)&.values_at(1, 2).join(' - ')
# NoMethodError: undefined method `join' for nil:NilClass
"Python is fascinating!".match(REGEX)&.values_at(1, 2)&.join(' - ')
# => nil
Аргументы
Существует три типа аргументов при отправке сообщения: позиционные аргументы, ключевые (или именованные) аргументы и аргумент блока. Каждое отправленное сообщение может использовать один, два или все типы аргументов, но аргументы должны быть предоставлены в этом порядке.
Все аргументы в Ruby передаются по ссылке и не вычисляются лениво.
Каждый аргумент отделяется ,:
my_method(1, '2', :three)
Аргументы могут быть выражением, аргументом типа хэш:
'key' => value
или ключевым аргументом:
key: value
Hash и ключевые аргументы должны быть непрерывными и должны появляться после всех позиционных аргументов, но могут быть смешаны:
my_method('a' => 1, b: 2, 'c' => 3)
Позиционные аргументы
Позиционные аргументы для сообщения следуют за именем метода:
my_method(argument1, argument2)
Во многих случаях скобки не нужны при отправке сообщения:
my_method argument1, argument2
Однако скобки необходимы, чтобы избежать неоднозначности. Это вызовет SyntaxError, потому что Ruby не знает, какой аргумент метода argument3 следует отправить:
method_one argument1, method_two argument2, argument3
Если определение метода имеет *argument дополнительные позиционные аргументы будут назначены argument в методе в виде Array.
Если в определении метода не указаны ключевые аргументы, ключевые или хэш-аргументы назначаются как один хэш последнему аргументу:
def my_method(options)
p options
end
my_method('a' => 1, b: 2) # prints: {'a'=>1, :b=>2}
Если указано слишком много позиционных аргументов, будет вызвано ArgumentError.
Аргументы по умолчанию
При определении метода с аргументами по умолчанию вам не нужно указывать все аргументы методу. Ruby заполнит отсутствующие аргументы в порядке следования.
Сначала рассмотрим простой случай, когда аргументы по умолчанию находятся справа. Рассмотрим этот метод:
def my_method(a, b, c = 3, d = 4) p [a, b, c, d] end
Здесь c и d имеют значения по умолчанию, которые Ruby применит за вас. Если вы передадите только два аргумента в этот метод:
my_method(1, 2)
Вы увидите, что Ruby выведет [1, 2, 3, 4].
Если вы передадите три аргумента:
my_method(1, 2, 5)
Вы увидите, что Ruby выведет [1, 2, 5, 4]
Ruby заполняет отсутствующие аргументы слева направо.
Ruby позволяет использовать значения по умолчанию посередине позиционных аргументов. Рассмотрим более сложный метод:
def my_method(a, b = 2, c = 3, d) p [a, b, c, d] end
Здесь b и c имеют значения по умолчанию. Если вы передадите только два аргумента в этот метод:
my_method(1, 4)
Вы увидите, что Ruby выведет [1, 2, 3, 4].
Если вы передадите три аргумента:
my_method(1, 5, 6)
Вы увидите, что Ruby выведет [1, 5, 3, 6].
Описание этого на словах становится сложным и запутанным. Я опишу это с помощью переменных и значений вместо этого.
Сначала 1 назначается a, затем 6 назначается d. Это оставляет только аргументы со значениями по умолчанию. Поскольку 5 еще не присвоено значение, оно передается b, и c использует свое значение по умолчанию 3.
Ключевые аргументы
Ключевые аргументы следуют за позиционными аргументами и разделяются запятыми, как и позиционные аргументы:
my_method(positional1, keyword1: value1, keyword2: value2)
Любые ключевые аргументы, не указанные, будут использовать значение по умолчанию из определения метода. Если ключевой аргумент указан, а метод не указал его, будет вызвано ArgumentError.
Аргумент блока
Аргумент блока отправляет замыкание из области вызова в метод.
Аргумент блока всегда последним при отправке сообщения методу. Блок отправляется в метод с помощью do ... end или { ... }:
my_method do # ... end
или:
my_method {
# ...
}
do end имеет более низкий приоритет, чем { } поэтому:
method_1 method_2 {
# ...
}
Отправляет блок в method_2, в то время как:
method_1 method_2 do # ... end
Отправляет блок в method_1. Обратите внимание, что в первом случае, если используются скобки, блок отправляется в method_1.
Блок будет принимать аргументы от метода, в который он был отправлен. Аргументы определяются аналогично тому, как метод определяет аргументы. Аргументы блока находятся в | ... | после открывающей do или {:
my_method do |argument1, argument2| # ... end
Локальные аргументы блока
Вы также можете объявлять локальные аргументы блока, используя ; в списке аргументов блока. Назначение локальному аргументу блока не переопределит локальные аргументы за пределами блока в области вызывающего кода:
def my_method
yield self
end
place = "world"
my_method do |obj; place|
place = "block"
puts "hello #{obj} this is #{place}"
end
puts "place is: #{place}"
Это выведет:
hello main this is block place is world
Таким образом, переменная place в блоке не является той же переменной place вне блока. Удаление ; place из аргументов блока дает такой результат:
hello main this is block place is block
Array Преобразование в аргументы
Учитывая следующий метод:
def my_method(argument1, argument2, argument3) end
Вы можете преобразовать массив Array в список аргументов с помощью оператора * (или splat):
arguments = [1, 2, 3] my_method(*arguments)
или:
arguments = [2, 3] my_method(1, *arguments)
Оба эквивалентны:
my_method(1, 2, 3)
Если метод принимает ключевые аргументы, оператор splat преобразует хэш в конце массива в ключевые аргументы:
def my_method(a, b, c: 3)
end
arguments = [1, 2, { c: 4 }]
my_method(*arguments)
Вы также можете использовать ** (описано ниже), чтобы преобразовать Hash в ключевые аргументы.
Если количество объектов в массиве Array не соответствует количеству аргументов для метода, будет вызвано ArgumentError.
Если оператор splat стоит в начале вызова, скобки должны быть использованы, чтобы избежать предупреждения.
Hash Преобразование в ключевые аргументы
Учитывая следующий метод:
def my_method(first: 1, second: 2, third: 3) end
Вы можете преобразовать хэш Hash в ключевые аргументы с помощью оператора **:
arguments = { first: 3, second: 4, third: 5 }
my_method(**arguments)
или:
arguments = { first: 3, second: 4 }
my_method(third: 5, **arguments)
Оба эквивалентны:
my_method(first: 3, second: 4, third: 5)
Если в определении метода используется ** для сбора произвольных ключевых аргументов, они не будут собраны *:
def my_method(*a, **kw) p arguments: a, keywords: kw end my_method(1, 2, '3' => 4, five: 6)
Выведет:
{:arguments=>[1, 2, {"3"=>4}], :keywords=>{:five=>6}}
В отличие от оператора splat, описанного выше, оператор ** не имеет общепринятого названия.
Proc Преобразование в блок
Учитывая метод, использующий блок:
def my_method yield self end
Вы можете преобразовать proc или lambda в аргумент блока с помощью оператора &:
argument = proc { |a| puts "#{a.inspect} was yielded" }
my_method(&argument)
Если оператор splat стоит в начале вызова, скобки должны быть использованы, чтобы избежать предупреждения.
В отличие от оператора splat, описанного выше, оператор & не имеет общепринятого названия.
Method Поиск метода
Когда вы отправляете сообщение, Ruby ищет метод, соответствующий имени сообщения для получателя. Методы хранятся в классах и модулях, поэтому поиск метода проходит по ним, а не по самим объектам.
Вот порядок поиска метода для класса или модуля получателя R:
-
Префиксные модули
Rв обратном порядке -
Для соответствующего метода в
R -
Включенные модули
Rв обратном порядке
Если R — это класс с суперклассом, это повторяется с суперклассом R до тех пор, пока не будет найден метод.
После того, как совпадение найдено, поиск метода прекращается.
Если совпадение не найдено, это повторяется с начала, но в поисках method_missing. По умолчанию method_missing — это BasicObject#method_missing, который вызывает NameError при вызове.
Если активны усовершенствования (экспериментальная функция), поиск метода изменяется. Подробности см. в документации по усовершенствованиям.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.