Spec-Zone.ru › Ruby 2.5

Вызов методов

Вызов метода отправляет сообщение объекту, чтобы он выполнил некоторую работу.

В Ruby вы отправляете сообщение объекту так:

my_method()

Обратите внимание, что скобки необязательны:

my_method

За исключением случаев, когда есть разница между использованием и опущением скобок, в этом документе используются скобки при наличии аргументов, чтобы избежать путаницы.

Этот раздел охватывает только вызов методов. См. также документацию по синтаксису определения методов.

Получатель

self — это получатель по умолчанию. Если вы не указываете получателя, self будет использован. Для указания получателя используйте .:

my_object.my_method

Это отправляет сообщение my_method получателю my_object. Любой объект может быть получателем, но в зависимости от видимости метода отправка сообщения может вызвать NoMethodError.

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

Вы также можете использовать :: для обозначения получателя, но это используется редко из-за потенциальной путаницы с :: для пространств имен.

Аргументы

При отправке сообщения существуют три типа аргументов: позиционные аргументы, ключевые (или именованные) аргументы и аргумент блока. Каждое отправленное сообщение может использовать один, два или все типы аргументов, но аргументы должны быть предоставлены в таком порядке.

Все аргументы в Ruby передаются по ссылке и не вычисляются лениво.

Каждый аргумент отделяется ,:

my_method(1, '2', :three)

Аргументы могут быть выражением, аргументом в виде хэша:

'key' => value

или ключевым аргументом:

key: value

Хэш и ключевые аргументы должны быть смежными и должны следовать за всеми позиционными аргументами, но могут быть смешаны:

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 в методе в виде массива.

Если определение метода не включает ключевые аргументы, ключевые или аргументы типа хэш присваиваются как один хэш последнему аргументу:

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

Преобразование массива в аргументы

Учитывая следующий метод:

def my_method(argument1, argument2, argument3)
end

Вы можете преобразовать массив в список аргументов с помощью оператора * (или 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)

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

Если количество объектов в массиве не соответствует количеству аргументов для метода, будет поднято исключение ArgumentError.

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

Преобразование хэша в ключевые аргументы

Учитывая следующий метод:

def my_method(first: 1, second: 2, third: 3)
end

Вы можете преобразовать хэш в ключевые аргументы с помощью оператора **:

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, описанного выше, оператор & не имеет общепринятого названия.

Поиск метода

Когда вы отправляете сообщение, 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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API