Методы
Методы реализуют функциональность вашей программы. Вот простое определение метода:
def one_plus_one 1 + 1 end
Определение метода состоит из ключевого слова def, имени метода, тела метода, return значения и ключевого слова end. При вызове метод выполнит тело метода. Этот метод возвращает 2.
Этот раздел посвящен только определению методов. См. также документацию по синтаксису вызова методов.
Method Имена
Method имена могут быть одним из операторов или должны начинаться с буквы или символа с установленным восьмым битом. Они могут содержать буквы, цифры, _ (подчеркивание) или символ с установленным восьмым битом. Принято использовать подчеркивания для разделения слов в многословных именах методов:
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, так как клавиши для их ввода есть на всех клавиатурах.
Method имена могут заканчиваться ! (восклицательный знак), ? (вопросительный знак) или = (знак равенства).
Методы с восклицательным знаком (! в конце имени метода) вызываются и выполняются как и любые другие методы. Однако, по соглашению, метод с восклицательным знаком считается небезопасным. В базовой библиотеке 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(self.a = 5) # prints 5
Фактическое возвращаемое значение будет возвращено при прямом вызове метода:
p send(:a=, 5) # prints 6
Область видимости
Стандартный синтаксис определения метода:
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
Array Разбиение массивов
Вы можете разбить (распаковать или извлечь значения из) массив Array с помощью дополнительных скобок в аргументах:
def my_method((a, b)) p a: a, b: b end my_method([1, 2])
Это выведет:
{:a=>1, :b=>2}
Если в аргументе в массиве Array есть дополнительные элементы, они будут проигнорированы:
def my_method((a, b)) p a: a, b: b end my_method([1, 2, 3])
Это выведет то же самое, что и выше.
Вы можете использовать * для сбора оставшихся аргументов. Это разбивает массив Array на первый элемент и остальные:
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 только в том случае, если можете использовать свой объект вместо массива Array.
Использование внутренних скобок использует только один из переданных аргументов. Если аргумент не является массивом Array, он будет назначен первому аргументу в разбиении, а оставшиеся аргументы в разбиении будут 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]
Аргумент массива должен быть последним позиционным аргументом, он должен стоять перед любыми именованными аргументами.
Аргумент массива захватывает хэш Hash как последний элемент, если вызывающий передал хэш после всех позиционных аргументов.
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 из блока, переданного в ваш метод. Дополнительные сведения см. в Proc.new.
Exception Обработка исключений
Методы имеют подразумеваемый блок обработки исключений, поэтому вам не нужно использовать 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.