Методы
Методы реализуют функциональность вашей программы. Вот простое определение метода:
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 (\x00).
Ниже приведены примеры допустимых методов Ruby:
def hello "hello" end def こんにちは puts "means hello in Japanese" end
Как правило, имена методов совместимы с US-ASCII, поскольку клавиши для их ввода существуют на всех клавиатурах.
Имена методов могут заканчиваться ! (восклицательный знак), ? (вопросительный знак) или = знаком равенства.
Методы с восклицательным знаком (! в конце имени метода) вызываются и выполняются так же, как и любой другой метод. Однако по соглашению метод с восклицательным знаком считается опасным. В библиотеке ядра Ruby опасный метод подразумевает, что если метод заканчивается восклицательным знаком (! ), это указывает, что в отличие от его эквивалента без восклицательного знака, он постоянно изменяет свой получатель. Почти всегда, в библиотеке ядра Ruby будет существовать метод без восклицательного знака (имя метода, НЕ заканчивающееся на ! ) для каждого метода с восклицательным знаком (имя метода, заканчивающееся на ! ), который не изменяет получателя. Эта конвенция обычно справедлива для библиотеки ядра Ruby, но может или не может быть справедлива для других библиотек 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.