необязательный аргумент ключевого слова необходим после аргумента splat, когда подэлементы не являются массивами - PullRequest
4 голосов
/ 14 марта 2019

Согласно этому посту , возможно иметь дополнительный аргумент ключевого слова после аргумента splat.Это работает, если аргумент splat представляет массив массивов, но не когда он является массивом хэшей

Например, если вызываемый метод определен как

def call(*scores, alpha: nil)
  puts scores
end

, тогда это работает

scores = [[1,2],[3,4]]
call(*scores)

, но это не

scores = [ {a: 1}, {b: 3}]
call(*scores)

, что дает следующее (с ruby ​​2.4.4)

ArgumentError: unknown keyword: b

, но это работает

scores = [ {a: 1}, {b: 3}]
call(*scores, alpha: nil)

Что здесь не так?

Ответы [ 2 ]

3 голосов
/ 14 марта 2019

Оператор splat разбивает массив на аргументы.

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

call([*scores]) #no error

Но также для иллюстрации, почему вы получили ошибку, посмотрите, что здесь происходит:

def call(*scores, alpha: nil)
  puts scores.inspect
end

call(*scores[0]) #=> #[[:a, 1]]

ОБНОВЛЕНО: Благодаря @Stefan, причина ошибки в том, что ваш метод принимает ключевое словоаргументы, что, видимо, известная ошибка.См. Распаковка аргументов ключевого слова (splat) в Ruby

Причина, по которой ваш последний пример работает, заключается в том, что, передавая 2-й аргумент вашему методу, splat обрабатывает первый аргумент как массив, а не пытаетсяразделить его на 2 аргумента.

Подробнее см. Ruby, Исходный код Splat?

Также см. https://www.rubyguides.com/2018/07/ruby-operators/#Ruby_Splat_Operator

2 голосов
/ 14 марта 2019

* преобразует элементы массива в список аргументов, поэтому:

call(*[{a: 1}, {b: 3}])

эквивалентно:

call({a: 1}, {b: 3})

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

call({a: 1}, b: 3)

Следовательно, {a: 1} рассматривается как позиционный аргумент и b: 3 (или {b: 3}) в качестве аргумента ключевого слова .И поскольку call не принимает аргумент ключевого слова с именем b, вы получаете ArgumentError: unknown keyword: b.

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

call({a:1}, {b:2}, {})

или:

call(*[{a:1}, {b:2}], {})

или

scores = [{a:1}, {b:2}]
call(*scores, {})

Есть запрос чтобы добавить «настоящие» аргументы ключевых слов в Ruby 3.


IMO, было бы правильнее использовать call(*scores, **{}) для обозначения «без аргументов ключевого слова», но из-за ошибка это в настоящее время не работает.Однако вы можете использовать call(*scores, **Hash.new)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...