Обзор операторов Single и Double splat

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

В этом посте я опишу, что такое операторы Ruby Single и Double splat, а также их опасное использование, которое я видел в продакшене. Цель состоит в том, чтобы показать способность оператора использовать его уверенно и выявлять опасные случаи во время проверки кода.

Сплат оператор

Существует два типа операторов Splat: одинарные (*) и двойные (**). Оба оператора имеют две основные функции: Construct и Spread out.

Оператор Single Splat (*) создает и распределяет массивы. Давайте посмотрим несколько примеров:

В предыдущем примере мы видим, что одиночный оператор splat захватывает элементы массива prime и распределяет их. Также полезно захватывать элементы массива и назначать их другой переменной, как показано в примере с переменной rest.

Мы также можем вставлять элементы массива в другой массив. В приведенном ниже примере primes элементов добавляются в массив numbers, начиная с позиции, где вызывается *primes.

Мы также можем использовать его для создания массива из одного элемента. Добавление Splat к значению преобразует значение в новый массив. См. следующий пример:

Двойной оператор Splat был выпущен в версии 2.0 Ruby и работает аналогично. Мы можем создавать и распространять хэши. См. следующий пример:

Эти операторы можно использовать в функциях. Либо в определении функции (в качестве аргумента), либо при вызове функции в качестве значения аргумента. Чтобы углубиться в эти два случая, давайте сначала посмотрим, какие типы аргументов может иметь функция Ruby.

Типы аргументов в Ruby

Функция может иметь различные типы аргументов:

  • Позиционные аргументы.
  • Аргументы ключевых слов (также известные как kwargs).
  • Аргументы Splat (одиночный и двойной оператор)

Позиционные аргументы самые простые. Аргументы ключевого слова имеют ключ (символ). Пример описывает тысячу слов:

arg_1 и arg_2 — позиционные аргументы, а key_1 и key_2 — kwargs.

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

Один оператор Splat в функции

Один оператор Splat при вызове функции

Оператор splat позволяет нам передавать элементы массива в функцию.

В этом примере вызов *arr расширяет элементы массива arr и передает их значения функции в качестве позиционных аргументов в том порядке, в котором они были заданы.

Обратите внимание, что если массив arr содержит больше значений, чем позиционные аргументы (2), произойдет ошибка (попробуйте передать arr = ["1", "2", "3"]). Точно так же, если вы передадите меньше аргументов, вы получите ошибку. Количество передаваемых аргументов должно соответствовать количеству позиционных аргументов, принимаемых функцией(с учетом аргументов со значением по умолчанию).

Один оператор Splat в качестве аргумента в определении функции

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

arg_1 — это аргумент, который использует оператор знака, что означает, что позиционные аргументы — это элементы массива arg_1. Следовательно, вы можете передать функции 0 или более позиционных аргументов.

Это не обязательно должен быть последний аргумент. Он может находиться в середине функции, как показано в следующем примере.

Оператор Double Splat в функции

Этот оператор очень похож на оператор Single, но предназначен для хэшей (и kwargs).

Двойной оператор Splat при вызове функции

Две важные вещи, о которых следует помнить:

  • Хэш должен иметь точно такие же ключи.
  • Хэш должен содержать ключи в виде символов, а не строк. Прочтите этот выпуск, если вам интересно узнать, почему в нем не используются строки.

Оператор Double Splat в качестве аргумента в определении функции:

Функция принимает 0 или более kwargs, которые являются частью hash. В отличие от оператора Single Splat, который может находиться в любой позиции, аргумент Double Splat должен быть последним в списке аргументов.

Вы, наверное, задавались вопросом, в чем разница между использованием Splat ** и просто переменной Hash в определении функции? Ну, есть несколько отличий:

  • Двойной знак не является обязательным. Вам не нужно передавать значение функции.
  • У Double Splat не может быть значения по умолчанию, а у простого Hash — может. Значением по умолчанию для Double Splat является неявно пустой хэш ({}).
  • Если в позиционных аргументах есть значения по умолчанию, результаты могут отличаться. См. следующий пример:

Комбинирование различных типов аргументов

Вы можете комбинировать одиночные и двойные операторы Splat, если Double Splat является последним аргументом и удовлетворяется требуемое количество аргументов. См. этот пример:

Будьте осторожны!

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

Давайте посмотрим пример. Найдите время, чтобы прочитать следующий фрагмент кода, и подумайте, почему этот код ужасен, прежде чем читать причину ниже.

Представьте, что у нас есть класс ActiveRecord Post, связанный с таблицей posts, содержащей три столбца id, title и description.

Класс PostSchema является оболочкой класса Post. У него есть конструктор, который принимает ровно три атрибута, которые имеет таблица.

У Service есть метод, который получает post_id и просматривает таблицу, чтобы найти сообщение. Если запись найдена, она получает свои атрибуты в виде символизированного хэша и присваивает их переменной attributes. Затем он создает PostSchema, используя двойной Splat с переменной attributes. Наконец, мы распечатываем файл PostSchema.

Вы заметили что-то не так с этим кодом? Если нет, найдите время, чтобы прочитать функцию print_post.

Что произойдет, если я изменю схему таблицы posts? Например, добавим новый столбец created_at в таблицу posts:

💥💥💥💥💥 Бум! Теперь тест провален! Причина в том, что оператор Splat теперь передает новый аргумент created_at, который конструктор PostSchema 'не поддерживает.

Это крайний случай, но такие случаи точно бывают! Другие ошибки могут быть вызваны различными факторами, такими как использование двойного Splat с ключами в виде строк, но я не видел много.

Заключение

Оператор splat полезен, и я предлагаю использовать его. Тем не менее, вы должны быть осторожны при использовании его внутри функций. Главное, убедитесь, что функция удовлетворяет размеру передаваемых аргументов. Кроме того, обратите особое внимание на значения по умолчанию и убедитесь, что ключи являются символами, если вы используете двойной символ Splat в качестве значения аргумента.