Что делает оператор double * (splat)

214

Вы видели функцию, объявленную так?

def foo a, **b
  ...
end

Я понимаю, что одиночный *оператор сплат. Что **значит?

Рой Ли
источник

Ответы:

373

В Ruby 2.0 введены ключевые аргументы, и они **действуют как *, но для ключевых слов. Возвращает хэш с парами ключ / значение.

Для этого кода:

def foo(a, *b, **c)
  [a, b, c]
end

Вот демо:

> foo 10
=> [10, [], {}]
> foo 10, 20, 30
=> [10, [20, 30], {}]
> foo 10, 20, 30, d: 40, e: 50
=> [10, [20, 30], {:d=>40, :e=>50}]
> foo 10, d: 40, e: 50
=> [10, [], {:d=>40, :e=>50}]
Dogbert
источник
44
Это прекрасно отвечает на вопрос, но у меня было небольшое дополнение. Так же, как оператор splat может использоваться в массиве, который вы передаете, двойной знак splat может использоваться в хешах. Если opts = {d: 40, e: 50}, то foo 10, opts, f: 60назначит {f: 60}к c, в то время как foo 10, **opts, f: 60будет назначать {d: 40, e: 50, f: 60}. Для достижения второго эффекта ранее вы должны были бы mergeявно использовать массивы.
Brymck
Я хотел бы предположить, что это полезно для установки дополнительных параметров хеш-функции для метода
bigpotato
Вероятно, стоит отметить, что если смешивать аргументы-ключевые слова с ключевыми словами-сплатами, ключевое слово-сплат должно идти после ключевых слов-аргументов.
MrMesees
43

Это оператор двойных сплатов , доступный с Ruby 2.0.

Он захватывает все аргументы ключевого слова (который также может быть простым хешем, который был идиоматическим способом эмулировать аргументы ключевого слова до того, как они стали частью языка Ruby)

def my_method(**options)
  puts options.inspect
end

my_method(key: "value")

Приведенный выше код выводится {key:value}на консоль.

Точно так же, как оператор одиночного сплата захватывает все обычные аргументы, но вместо массива вы получаете хеш .

Пример из жизни:

Например, в Rails cycleметод выглядит так:

def cycle(first_value, *values)
  options = values.extract_options!
  # ...
end

Этот метод можно назвать так: cycle("red", "green", "blue", name: "colors").

Это довольно распространенный шаблон: вы принимаете список аргументов, а последний - хэш опций, который можно извлечь, например, используя ActiveSupport extract_options!.

В Ruby 2.0 вы можете упростить эти методы:

def cycle(first_value, *values, **options)
  # Same code as above without further changes!
end

По общему признанию, это лишь незначительное улучшение, если вы уже используете ActiveSupport, но для простого Ruby код получает довольно много краткости.

Даниэль Риковски
источник
20

Кроме того, вы можете использовать его на стороне вызывающего абонента следующим образом:

def foo(opts); p opts end
bar = {a:1, b:2}

foo(bar, c: 3)
=> ArgumentError: wrong number of arguments (given 2, expected 1)

foo(**bar, c: 3)
=> {:a=>1, :b=>2, :c=>3}
kuboon
источник
5
Вау, двойная дробь аналогична оператору распространения объектов ES6.
mpoisot
1
Спасибо, это подтверждение, которое я искал.
Кортекс