Вы видели такую функцию?
def foo a, **b
...
end
Я понимаю, что единственный *
- это оператор splat. Что значит **
?
Вы видели такую функцию?
def foo a, **b
...
end
Я понимаю, что единственный *
- это оператор splat. Что значит **
?
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}]
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
d массивов.
- person brymck; 03.11.2013
Это оператор двойной знак, доступный начиная с Ruby 2.0.
Он фиксирует все аргументы ключевого слова (которые также могут быть простым хешем, что было идиоматическим способом имитации аргументов ключевого слова до того, как они стали частью языка Ruby)
def my_method(**options)
puts options.inspect
end
my_method(key: "value")
Приведенный выше код выводит {key:value}
на консоль.
Точно так же, как единственный оператор splat захватывает все обычные аргументы, но вместо массива вы получаете хэш.
Пример из жизни:
Например, в 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 код становится довольно лаконичным.
Кроме того, вы можете использовать его на стороне вызывающего абонента следующим образом:
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}