Методы
Методы реализуют функциональность вашей программы. Вот простое определение метода:
def one_plus_one 1 + 1 end
Определение метода состоит из ключевого слова def, имени метода, тела метода, return значения и ключевого слова end. При вызове метода будет выполнено тело метода. Этот метод возвращает 2.
Этот раздел посвящен только определению методов. См. также документацию по синтаксису вызова методов.
Методы Имена
Методы могут быть одним из операторов или должны начинаться с буквы или символа с установленным восьмым битом. Они могут содержать буквы, цифры, символ _ (подчеркивание) или символ с установленным восьмым битом. Конвенция заключается в использовании подчеркиваний для разделения слов в имени метода из нескольких слов:
def method_name puts "use underscores to separate words" end
Ruby-программы должны быть написаны в наборе символов, совместимом с US-ASCII, таком как UTF-8, ISO-8859-1 и т. д. В таких наборах символов, если установлен восьмой бит, это указывает на расширенный символ. Ruby позволяет именам методов и другим идентификаторам содержать такие символы. Ruby-программы не могут содержать некоторые символы, такие как ASCII NUL (<code>x00<code>).
Вот примеры допустимых Ruby-методов:
def hello "hello" end def こんにちは puts "means hello in Japanese" end
Как правило, имена методов совместимы с US-ASCII, так как для их ввода существуют клавиши на всех клавиатурах.
Методы могут заканчиваться символом ! (восклицательный знак), ? (вопросительный знак) или = знаком равенства.
Методы с восклицательным знаком (! в конце имени метода) вызываются и выполняются как любые другие методы. Однако по соглашению метод с восклицательным знаком считается опасным. В библиотеке Ruby core опасный метод подразумевает, что если метод заканчивается восклицательным знаком (!), это указывает на то, что, в отличие от своего аналога без восклицательного знака, он постоянно изменяет свой получатель. Почти всегда в библиотеке Ruby core будет существовать метод без восклицательного знака (имя метода, НЕ заканчивающееся на !) для каждого метода с восклицательным знаком (имя метода, заканчивающегося на !), который не изменяет получатель. Эта конвенция, как правило, верна для библиотеки Ruby core, но может/может не соблюдаться для других Ruby-библиотек.
Методы, заканчивающиеся вопросительным знаком, по соглашению возвращают булево значение. Но они не всегда возвращают только true или false. Часто они могут возвращать объект для обозначения истинного значения (или «истинного» значения).
Методы, заканчивающиеся знаком равенства, указывают на метод присваивания. Для методов присваивания возвращаемое значение игнорируется, вместо него возвращаются аргументы.
Вот имена методов для различных операторов Ruby. Каждый из этих операторов принимает только один аргумент. После оператора указано типичное использование или название оператора. Создание альтернативного значения для оператора может привести к путанице, так как пользователь ожидает, что плюс будет складывать, минус — вычитать и т. д. Кроме того, вы не можете изменить приоритет операторов.
-
+ -
сложение
-
- -
вычитание
-
* -
умножение
-
** -
возведение в степень
-
/ -
деление
-
% -
деление по модулю, String#%
-
& -
И
-
^ -
ИСКЛЮЧАЮЩЕЕ ИЛИ (XOR)
-
>> -
сдвиг вправо
-
<< -
сдвиг влево, добавление
-
== -
равно
-
!= -
не равно
-
=== -
равенство по типу. См. Object#===
-
=~ -
сопоставление шаблонов. (Не только для регулярных выражений)
-
!~ -
не соответствует
-
<=> -
сравнение, оператор «корабль». См. Comparable
-
< -
меньше
-
<= -
меньше или равно
-
> -
больше
-
>= -
больше или равно
Для определения унарных методов минус, плюс, тильда и не (!) следует поместить оператор перед @, как в +@ или !@:
class C
def -@
puts "you inverted this object"
end
end
obj = C.new
-obj # prints "you inverted this object"
Унарные методы принимают ноль аргументов.
Кроме того, могут быть определены методы для ссылки на элемент и присваивания: [] и []= соответственно. Оба могут принимать один или несколько аргументов, а ссылка на элемент может не принимать никаких аргументов.
class C
def [](a, b)
puts a + b
end
def []=(a, b, c)
puts a * b + c
end
end
obj = C.new
obj[2, 3] # prints "5"
obj[2, 3] = 4 # prints "10"
Возвращаемые значения
По умолчанию метод возвращает последнее выражение, которое было вычислено в теле метода. В приведенном выше примере последним (и единственным) вычисленным выражением был простой итог 1 + 1. Ключевое слово return может использоваться для явного указания того, что метод возвращает значение.
def one_plus_one return 1 + 1 end
Его также можно использовать, чтобы метод возвращал значение до вычисления последнего выражения.
def two_plus_two return 2 + 2 1 + 1 # this expression is never evaluated end
Обратите внимание, что для методов присваивания возвращаемое значение всегда будет игнорироваться. Вместо этого возвращается аргумент:
def a=(value) return 1 + value end p(a = 5) # prints 5
Область видимости
Стандартный синтаксис для определения метода:
def my_method # ... end
добавляет метод в класс. Вы можете определить метод экземпляра для определенного класса с помощью ключевого слова class:
class C
def my_method
# ...
end
end
Метод может быть определен для другого объекта. Вы можете определить «метод класса» (метод, определенный для класса, а не для экземпляра класса) следующим образом:
class C
def self.my_method
# ...
end
end
Однако это просто частный случай большей синтаксической возможности Ruby — возможность добавлять методы к любому объекту. Классы являются объектами, поэтому добавление методов класса — это просто добавление методов к объекту Class.
Синтаксис добавления метода к объекту следующий:
greeting = "Hello" def greeting.broaden self + ", world!" end greeting.broaden # returns "Hello, world!"
self — это ключевое слово, которое относится к текущему объекту, рассматриваемому компилятором, что может сделать использование self при определении метода класса выше немного более понятным. В самом деле, пример добавления метода hello к классу String можно переписать следующим образом:
def String.hello "Hello, world!" end
Метод, определенный таким образом, называется «сингулярным методом». broaden будет существовать только для экземпляра строки greeting. Другие строки не будут иметь broaden.
Переопределение
Когда Ruby встречает ключевое слово def, он не считает это ошибкой, если метод уже существует: он просто переопределяет его. Это называется переопределением. Подобно расширению базовых классов, эта потенциально опасная возможность должна использоваться с осторожностью, так как она может привести к непредвиденным результатам. Например, рассмотрим эту сессию irb:
>> "43".to_i => 43 >> class String >> def to_i >> 42 >> end >> end => nil >> "43".to_i => 42
Это фактически саботирует любой код, который использует метод String#to_i для анализа чисел из строк.
Аргументы
Метод может принимать аргументы. Список аргументов следует за именем метода:
def add_one(value) value + 1 end
При вызове пользователем метода add_one должен быть предоставлен аргумент. Аргумент — это локальная переменная в теле метода. Метод затем добавит к этому аргументу единицу и вернёт полученное значение. Если задан аргумент 1, этот метод вернёт значение 2.
Скобки вокруг аргументов необязательны:
def add_one value value + 1 end
Несколько аргументов разделяются запятыми:
def add_values(a, b) a + b end
При вызове аргументы должны быть предоставлены в точном порядке. Другими словами, аргументы являются позиционными.
Значения по умолчанию
Аргументы могут иметь значения по умолчанию:
def add_values(a, b = 1) a + b end
Значение по умолчанию не обязательно должно быть первым, но аргументы со значениями по умолчанию должны быть сгруппированы вместе. Это нормально:
def add_values(a = 1, b = 2, c) a + b + c end
Это вызовет ошибку SyntaxError:
def add_values(a = 1, b, c = 1) a + b + c end
Разбиение массива
Вы можете разбить (распаковать или извлечь значения из) массив, используя дополнительные скобки в аргументах:
def my_method((a, b)) p a: a, b: b end my_method([1, 2])
Это выведет:
{:a=>1, :b=>2}
Если в массиве аргумента есть дополнительные элементы, они будут проигнорированы:
def my_method((a, b)) p a: a, b: b end my_method([1, 2, 3])
Это выведет тот же результат, что и выше.
Вы можете использовать * для сбора оставшихся аргументов. Это разделяет массив на первый элемент и остальные:
def my_method((a, *b)) p a: a, b: b end my_method([1, 2, 3])
Это выведет:
{:a=>1, :b=>[2, 3]}
Аргумент будет разбит, если он отвечает методу to_ary. Вы должны определять to_ary только если можете использовать свой объект вместо массива.
Использование внутренних скобок использует только один из переданных аргументов. Если аргумент не является массивом, он будет присвоен первому аргументу в разбиении, а оставшиеся аргументы в разбиении будут nil:
def my_method(a, (b, c), d) p a: a, b: b, c: c, d: d end my_method(1, 2, 3)
Это выведет:
{:a=>1, :b=>2, :c=>nil, :d=>3}
Вы можете произвольно вкладывать разбиения:
def my_method(((a, b), c)) # ... end
Аргумент массива/словаря
Предварительный аргумент * приводит к преобразованию всех оставшихся аргументов в массив:
def gather_arguments(*arguments) p arguments end gather_arguments 1, 2, 3 # prints [1, 2, 3]
Аргумент массива должен быть последним позиционным аргументом, он должен предшествовать любым аргументам-ключам.
Аргумент массива захватит словарь как последний элемент, если вызывающий метод передал словарь после всех позиционных аргументов.
gather_arguments 1, a: 2 # prints [1, {:a=>2}]
Однако это происходит только в том случае, если метод не объявляет никаких аргументов-ключей.
def gather_arguments_keyword(*positional, keyword: nil) p positional: positional, keyword: keyword end gather_arguments_keyword 1, 2, three: 3 #=> raises: unknown keyword: three (ArgumentError)
Также обратите внимание, что пустой * может использоваться для игнорирования аргументов:
def ignore_arguments(*) end
Аргументы-ключи
Аргументы-ключи похожи на позиционные аргументы со значениями по умолчанию:
def add_values(first: 1, second: 2) first + second end
Произвольные аргументы-ключи будут приняты с **:
def gather_arguments(first: nil, **rest)
p first, rest
end
gather_arguments first: 1, second: 2, third: 3
# prints 1 then {:second=>2, :third=>3}
При вызове метода с аргументами-ключами аргументы могут быть представлены в любом порядке. Если вызывающий метод передаёт неизвестный аргумент-ключ, генерируется ArgumentError.
При смешивании аргументов-ключей и позиционных аргументов все позиционные аргументы должны предшествовать любым аргументам-ключам.
Блок-аргумент
Блок-аргумент обозначается & и должен быть последним:
def my_method(&my_block) my_block.call(self) end
Чаще всего блок-аргумент используется для передачи блока другому методу:
def each_item(&block) @items.each(&block) end
Если вы собираетесь только вызвать блок и не будете иначе его обрабатывать или отправлять в другой метод, использование yield без явного параметра блока предпочтительнее. Этот метод эквивалентен первому методу в этом разделе:
def my_method yield self end
Также существует производительный выигрыш при использовании yield вместо вызова параметра блока. Когда блок-аргумент присваивается переменной, создаётся объект Proc, который содержит блок. При использовании yield этот объект Proc не создаётся.
Если вам нужно использовать блок только иногда, вы можете использовать Proc.new для создания прокси из блока, переданного в ваш метод. См. Proc.new для получения дополнительной информации.
Исключение Обработка
Методы имеют неявный блок обработки исключений, поэтому вам не нужно использовать begin или end для обработки исключений. Это:
def my_method
begin
# code that may raise an exception
rescue
# handle exception
end
end
Можно переписать как:
def my_method # code that may raise an exception rescue # handle exception end
Если вы хотите перехватить исключение только для части вашего метода, используйте begin и end. Для получения более подробной информации см. страницу по обработке исключений.
Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.