Вы видели функцию, объявленную как это?
def foo a, **b
...
end
Я понимаю, что один *
- это оператор splat. Что означает **
?
Вы видели функцию, объявленную как это?
def foo a, **b
...
end
Я понимаю, что один *
- это оператор splat. Что означает **
?
Ruby 2.0 представил аргументы ключевого слова, а **
действует как *
, но для аргументов ключевого слова. Он возвращает Hash с парами ключ/значение.
Для этого кода:
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}]
Это оператор double splat, доступный с 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}
Для целых чисел ** означает показатель степени т.е. 2 ** 3 совпадает с 2 ^ 3