Spec-Zone.ru › Ruby 2.3

Методы

Методы реализуют функциональность вашей программы. Вот простое определение метода:

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

Аргумент Array/Hash

Представление аргумента с * приводит к преобразованию любых оставшихся аргументов в массив:

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.

Spec-Zone.ru

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