Что делает оператор * — «звездочка» в Ruby?
декабря 8, 2010 | Published in Ruby, Основы | 5 Comments
Ruby — язык, который полон сюрпризов, чаще всего приятных. Одной из интересных идиом в Ruby является унарный оператор «звездочка» - *, он же asterisk и splat. К сожалению не все умеют с ним работать и не все понимают что он делает. Мне больше всего нравится название asterisk, поэтому я буду использовать его далее по тексту.
Зачем же необходим оператор asterisk? Вот несколько возможных вариантов использования осортированных по частоте применения:
1. Передача произвольного числа аргументов в метод
Методы могут не получать аргументы, получать строго определенное количество аргументов и получать произвольное количество аргументов. asterisk используется для того, чтобы предоставить методам в языке Ruby получать произвольное, т.е. заранее неизвестное количество аргументов, или набор однотипных аргументов, в том смысле, что над всеми этими аргументами производятся одни и те же действия.
def example_method(a,b,*c,d) p a p b p c p d end example_method(1,2,3,4,5,6,7) # 1 # 2 # [3,4,5,6] # 7
В порядке следования аргументов метода им (аргументам) присваиваются значения. Как вы видите, передаваемых в метод аргументов больше, чем указано при объявлении метода. С этим в данном случае и справляется оператор asterisk, который дает понять интерпретатору Ruby, то,что все «лишние» значения необходимо поместить в массив c.
Давайте за закрепления информации рассмотрим более сложный и практичный пример: представьте, что нам необходимо составить таблицу умножения в которой неизвестное заранее количество чисел будет перемножено на числа из известного диапазона:
def mktable(f, l, *nums) (f..l).each {|s| nums.each {|n| printf "%4d", s*n}; puts} end mktable(1,5,3,4,5,8,9,56)
Здесь nums будет содержать массив [3,4,5,8,9,56].
2. Передача аргумента — массива в метод
Часто методы созданы таким образом, что не расчитаны на получение массива аргументов, что нам необходимо сделать, если мы хотим воспользоваться таким методом, но все необходимые аргументы у нас содержатся в массиве?
Можем пойти самым очевидным путем и присвоить аргументы хранящиеся в массиве переменным, которые и будут переданы методу:
our_args = [6.29, 6.3] a = our_args[0] b = our_args[1] def min (a, b) a < b ? m = a : m = b puts m end min a, b # а можем, используя оператор asterisk, так: our_args = [6.29, 6.3] def min (a, b) a < b ? m = a : m = b puts m end min *our_args
Второй вариант значительно удобней, это будет особенно заметно при большом количестве аргументов.
3. Множественное присваивание значений переменным
arr = ["Armani", "Gucci", "Celvin Klein"] a, b = arr # a = "Armani", b = "Gucci", а Calvin Klein куда-то пропадет... a, *b = arr # a = "Armani", b = "Gucci" # a = "Armani", b = ["Gucci", "Calvin Klein"], Calvin Klein никуда не пропал =)
Очевидно, что если поменять a и b местами, то b будет содержать массив из первых двух элементов arr, в то время как a будет содержать последний элемент.
4. Преобразования Array в Hash и Hash в Array
Преобразование массива в хэш:
a = [:name, "Vladimir", :login, "vladimir_90", :pswd, 123456] h = Hash[*a] #h = {:name=>"Vladimir", :login=>"vladimir_90", :pswd=>123456}
Преобразование хэша в массив:
h = {:name=>"Vladimir", :login=>"vladimir_90", :pswd=>123456} a = [*h] #a = [[:name, "Vladimir"], [:login, "vladimir_90"], [:pswd, 123456]]
Такие преобразования бывают очень полезны, например, при парсинге xml, html, csv и других текстовых форматов данных, которые могу быть представлены в виде: ключ — значение.
Лучшая благодарность автору — ваши комментарии!
декабря 8, 2010 at 19:42 (#)
Первый пункт знал, а второй, третий и четвёртый нет. Спасибо!
декабря 8, 2010 at 20:10 (#)
c0va32, всегда пожалуйста!
декабря 9, 2010 at 00:24 (#)
В #4 a=[*h] можно заменить на тривиальное a=h.to_a, например. А так спасибо — весьма интересно.
PS. s/Celvin/Calvin/ :)
декабря 9, 2010 at 23:06 (#)
Scrill, спасибо, поправил.
марта 4, 2011 at 02:37 (#)
Всё же считаю что вы должны использовать название splat, потому что оно использовано в Programming Ruby 1.9 и наиболее часто употребляется в этом значении, потому в будущем вам пригодится именно это название для данного оператора.