Какой смысл использовать двойную косую черту Руби (`**`) в вызовах методов?

С помощью одного знака мы можем расширить массив на несколько аргументов, что сильно отличается от прямой передачи массива:

def foo(a, b = nil, c = nil)
  a
end

args = [1, 2, 3]

foo(args)  # Evaluates to foo([1, 2, 3]) => [1, 2, 3]
foo(*args) # Evaluates to foo(1, 2, 3)   => 1

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

def foo(key:)
  key
end

args = { key: 'value' }

foo(args)   # Evaluates to foo(key: 'value') => 'value'
foo(**args) # Evaluates to foo(key: 'value') => 'value'

Помимо приятной симметрии, есть ли практическая причина использовать двойные сплаты для вызовов методов? (Обратите внимание, что это отличается от использования их в определении метода)

1 ответ

Решение

Пример с одним аргументом является вырожденным случаем.

Глядя на нетривиальный случай, вы можете быстро увидеть преимущество наличия нового ** оператор:

def foo (args)
  return args
end

h1 = { b: 2 }
h2 = { c: 3 }

foo(a: 1, **h1)       # => {:a=>1, :b=>2}
foo(a: 1, **h1, **h2) # => {:a=>1, :b=>2, :c=>3}
foo(a: 1, h1)         # Syntax Error: syntax error, unexpected ')', expecting =>
foo(h1, h2)           # ArgumentError: wrong number of arguments (2 for 1)

С использованием ** Оператор позволяет нам объединять существующие хеши вместе в командной строке вместе с буквальными аргументами ключ-значение. (То же самое относится и к использованию * с массивами аргументов, конечно.)

К сожалению, вы должны быть осторожны с этим поведением, в зависимости от того, какую версию Ruby вы используете. В Ruby 2.1.1, по крайней мере, была ошибка, из-за которой разбитый хэш был бы разрушительно изменен, хотя с тех пор он был исправлен.

Другие вопросы по тегам