Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Ruby / Ruby-новые грани.doc
Скачиваний:
139
Добавлен:
06.06.2015
Размер:
821.25 Кб
Скачать

4.13.3 Параметры Array

В Ruby есть возможность пометить последний параметр метода знаком «звездочка»:

  defmethod(*args)

  ...

  end

что указывает Ruby специальным образом обрабатывать аргументы такого метода при вызове. Звездочка перед именем параметра означает, что параметр будет иметь тип Array, но при вызове метода аргументы будут задаваться в виде последовательности значений. Эта последовательность будет автоматически преобразована в объект Array, и этот объект будет передан в метод в виде одного аргумента. Например:

  def method(*args)

    puts args.join(’, ’)

  end

  

  method(1, ’2’, :three, 4)      # => 1, 2, three, 4

Или, с учетом необязательности скобок:

  method 1, ’2’, :three, 4

Именно за счет таких параметров работают многие DSL-образующие методы в Ruby. Например, упоминавшийся выше метод attr_accessor всего лишь вызывает для каждого своего аргумента стандартный метод attr. Простейшая реализация attr_accessor имеет вид:

  class Object

    ...

    def Object.attr_accessor(*attrs)

      attrs.each do |a| attr(a, true) end

    end

    ...

  end

Нужно отметить, что запись *something является стандартной конструкцией Ruby, означающей «разворачивание» объекта Array в последовательность содержащихся в нем элементов, что часто используется в параллельных присваиваниях. Например:

  a = [1, 2, 3, 4]

  b, c, d = *a

  b                                # => 1

  c                                # => 2

  d                                # => 3

Здесь первые три значения из массива a были присвоены трем переменным-приемникам. Четвертое значение было проигнорировано, поскольку приемников было всего три. Если нужно, чтобы переменная d получила все оставшиеся в a значения, то следует использовать запись *d:

  a = [1, 2, 3, 4]

  b, c, *d = *a

  b                                # => 1

  c                                # => 2

  d                                # => [3, 4]

Поэтому запись параметра Array в виде *args согласуется с операцией «разворачивания» значения Array посредством операции «звездочка», что также проявляется при необходимости передачи параметру Array значений из какого-то вектора:

  a = [ 1, 2, 3, 4, 5 ]

  method *a

Например, это может быть необходимо, если параметр Array нужно передать в другой метод в качестве аналогичного параметра Array:

  def method(*args)

    puts *args

  end

Параметры Array оказываются полезными еще в нескольких случаях. Например, при перекрытии метода базового класса, когда список параметров метода не важен. Скажем, при создании собственных классов в unit-тестах иногда бывает необходимо определить собственный конструктор. Но его формат должен в точности совпадать с форматом конструктора базового типа TestCase из стандартной библиотеки, поскольку объекты unit-тесты создаются не программистом, а фреймворком. Чтобы не зависеть от формата конструктора базового типа TestCase стандартной библиотеки, можно использовать параметр Array:

  class TC_MyUnitTest < Test::Unit::TestCase

    # Неважно, какие аргументы передаются в конструктор unit-теста.

    # Пусть они выглядят как параметр Array.

    definitialize(*args)

      # Конструктор базового типа получает все аргументы в исходном виде.

      super(*args)

      ...

    end

    ...

  end

Еще одним случаем использования параметров Array являются методы вроде send и method_missing, которым приходится передавать неизвестные изначально списки аргументов. Поэтому последним параметром этих методов является именно параметр Array:

  # obj.send(symbol [, args...]) => obj

  #

  # Создание объекта типа Range путем ручной отправки сообщения :new

  # классу Range со всеми необходимыми параметрами.

  r = Range.send(:new, 1, 4, true)   # => 1...4

Соседние файлы в папке Ruby