Зачем мне нужна звездочка перед массивом?

Я понятия не имею, является ли это проблемой Hash или проблемой Array, но я не понимаю, почему в третьем примере требуется знак звездочки (*), чтобы получить хэш, заполненный данными. Без него выводится пустой хэш.

# -*- coding: utf-8 -*-
require 'pp'
pp [[:first_name, 'Shane'], [:last_name, 'Harvie']]
# => [[:first_name, "Shane"], [:last_name, "Harvie"]]

pp [[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten
# => [:first_name, "Shane", :last_name, "Harvie"]

pp Hash[*[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]
# => {:first_name=>"Shane", :last_name=>"Harvie"}

pp Hash[[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten]
# => {}

Ниже приведено объяснение метода.

--------------------------------------------------------------- Hash::[]
     Hash[ [key =>|, value]* ]   => hash

     From Ruby 1.8
------------------------------------------------------------------------
     Creates a new hash populated with the given objects. Equivalent to
     the literal +{ _key_, _value_, ... }+. Keys and values occur in
     pairs, so there must be an even number of arguments.

        Hash["a", 100, "b", 200]       #=> {"a"=>100, "b"=>200}
        Hash["a" => 100, "b" => 200]   #=> {"a"=>100, "b"=>200}
        { "a" => 100, "b" => 200 }     #=> {"a"=>100, "b"=>200}

Ответы

Ответ 1

Оператор splat (т.е. *) превращает то, что в противном случае было бы массивом в список для назначения в хеше. Вы должны дать оператору [] фактический список, чтобы он превратился в пары ключ/значение хэша. (См. Ниже ссылку на краткое описание оператора splat, который действительно может это сделать (разматывать массив в список) или наоборот (собрать список в массив).

Как вы делали это выше, вы даете Hash[] нечетное количество элементов, а именно один массив. (Подумайте о том, что производит [[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten. Он дает [:first_name, 'Shane', :last_name, 'Havie'].) Как указано в ваших документах, оператор [] должен иметь четное число элементов. Обратите внимание, что работает следующее (хотя и бесполезное):

>> Hash[[[:first_name, 'Shane'], [:last_name, 'Harvie']].flatten, 1]
=> {[:first_name, "Shane", :last_name, "Harvie"]=>1}

(Мне непонятно, почему вы не получаете ошибку "нечетное количество аргументов для Hash" при использовании кода, который у вас выше, как вы делаете, если вы попробуете Hash[1].)

Более простой пример может сделать его более ясным. Сначала, передавая один элемент, массив. Открытие массива с помощью *, чтобы передать Hash[] список элементов:

>> Hash[['foo', 'bar', 'bizz', 'buzz']]
=> {}
>> Hash[*['foo', 'bar', 'bizz', 'buzz']]
=> {"foo"=>"bar", "bizz"=>"buzz"}

См. это сообщение в блоге для более полного объяснения. Вы также можете найти эту короткую запись о операторе splat.