Ruby - переопределение/включение множественного присвоения (например, `a, b, c = d, e, f`)

В рубине вы можете сделать это:

d = [1, 2, 3]
a, b, c = d

a, b и c будут получать значения 1, 2 и 3 соответственно.

d, в этом случае в Array и ruby ​​знает, чтобы назначить его содержимому a, b и c. Но если d был Fixnum, например, только a было бы присвоено значение d, а b и c было бы назначено nil.

Какие свойства d позволяют использовать его для множественного присвоения? В моем изучении до сих пор я смог сделать экземпляры подклассов Array таким образом.

Ответ 1

Это очень недокументированная функция, и я буду использовать ее с осторожностью, но здесь мы идем. Из книги "Язык программирования Ruby":

Когда имеется несколько значений l и Руби пытается попытаться расширьте rvalue в список значения для назначения. Если это значение массив, Ruby расширяет массив так, чтобы каждый элемент становится его собственным значением r. Если значение не является массивом, но реализует метод to_ary, Ruby вызывает этот метод, а затем расширяется массив, который он возвращает.

В Ruby 1.8 это метод to_ary, в документации Ruby 1.9 говорит, что он вызывает to_splat, но я не тестировал (нет 1.9 в этой машине) Он didn работайте как ожидалось. Итак, вы должны определить метод to_ary в вашем объекте.

class Week
  def to_ary
    %w(monday tuesday wednesday thursday friday saturday sunday)
  end
end

mon, tue, wed, thu, *weekend = Week.new

* %w(...) Является специальным обозначением для массива слов, если вы ленивы писать ['monday', 'tuesday' ...]

Ответ 2

Какие свойства d позволяют использовать его для множественного присвоения?

d должен быть Array или быть конвертируемым в один. IOW это должен быть либо экземпляр класса Array (или любого из его подклассов), либо отвечать на сообщение to_ary:

def (not_an_array = Object.new).to_ary; [:foo, :bar, :baz] end

foo, bar, baz = not_an_array

foo # => :foo
bar # => :bar
baz # => :baz

Обратите внимание, что это экземпляр более общего шаблона в Ruby: почти все методы в Ruby, которые ожидают, что Array, a String, Integer или Float также будут принимать объект, который отвечает до to_ary, to_str, to_int или to_float. И ваши собственные методы тоже должны быть кстати!