Spec-Zone.ru › Ruby 2.6

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

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

В 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.

Spec-Zone.ru

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