Я как раз читал статью в блоге и заметил, что автор использовал tap
во фрагменте что-то вроде:
user = User.new.tap do |u|
u.username = "foobar"
u.save!
end
У меня вопрос, в чем именно преимущество или преимущество использования tap
? Не мог я просто сделать:
user = User.new
user.username = "foobar"
user.save!
или еще лучше:
user = User.create! username: "foobar"
User.new.tap &:foobar
user = User.create!(username: 'foobar')
в этом случае что-то вроде бы было самым ясным и кратким :) - последний пример из вопроса.user
. Также аргумент, что «Читателю не нужно читать то, что находится внутри блока, чтобы узнать, что экземплярuser
создан». не имеет веса, потому что в первом блоке кода читателю также нужно прочитать только первую строку, «чтобы узнать, что экземплярuser
создан».Другой случай использования касания - это манипулирование объектом перед его возвратом.
Итак, вместо этого:
мы можем сохранить лишнюю строку:
В некоторых ситуациях этот метод может сэкономить более одной строки и сделать код более компактным.
источник
some_object.tap(&:serialize)
Использование тапа, как это сделал блоггер, - это просто удобный метод. Возможно, в вашем примере это было излишним, но в тех случаях, когда вы хотите сделать кучу вещей с пользователем, tap, возможно, может обеспечить более понятный интерфейс. Итак, возможно, это может быть лучше в следующем примере:
Использование приведенного выше позволяет быстро увидеть, что все эти методы сгруппированы вместе, поскольку все они относятся к одному и тому же объекту (пользователю в этом примере). Альтернативой может быть:
Опять же, это спорно - но дело может быть сделано, что вторая версия выглядит немного хаотичным, и занимает немного больше человеческого синтаксический, чтобы увидеть, что все эти методы называют на одном объекте.
источник
user = User.new, user.do_something, user.do_another_thing
... не могли бы вы расширить, почему можно это сделать?tap
моему опыту, использование никогда не приносило никаких преимуществ. Наuser
мой взгляд , создание локальной переменной и работа с ней намного чище и читабельнее.u = user = User.new
а затем использовалиu
для вызовов настройки, это больше соответствовало бы первому примеру.Это может быть полезно при отладке серии
ActiveRecord
связанных областей видимости.Это упрощает отладку в любой точке цепочки без необходимости хранить что-либо в локальной переменной и не требуя значительного изменения исходного кода.
И, наконец, используйте его как быстрый и ненавязчивый способ отладки, не нарушая нормального выполнения кода :
источник
Визуализируйте свой пример в функции
Такой подход сопряжен с большим риском обслуживания, в основном с неявным возвращаемым значением. .
В этом коде вы зависите от
save!
возврата сохраненного пользователя. Но если вы используете другую утку (или ваша текущая эволюционирует), вы можете получить другие вещи, например, отчет о статусе завершения. Поэтому изменения в утке могут нарушить код, чего не произойдет, если вы обеспечите возвращаемое значение простымuser
или коснитесь.Я довольно часто видел подобные инциденты, особенно с функциями, в которых возвращаемое значение обычно не используется, за исключением одного темного угла с ошибками.
Неявное возвращаемое значение, как правило, является одним из тех случаев, когда новички склонны ломать вещи, добавляя новый код после последней строки, не замечая эффекта. Они не понимают, что на самом деле означает приведенный выше код:
источник
user
?User.new.tap{ |u| u.username = name; u.save! }
Если вы хотите вернуть пользователя после установки имени пользователя, вам нужно будет сделать
С
tap
вы могли бы спасти это неловкое возвращениеисточник
Object#tap
Для меня это самый распространенный вариант использования .user = User.new.tap {|u| u.username = 'foobar' }
В результате код становится менее загроможденным, поскольку объем переменной ограничивается только той частью, где это действительно необходимо. Кроме того, отступ внутри блока делает код более читабельным, поскольку соответствующий код хранится вместе.
Описание
tap
говорит :Если мы поищем исходный код rails для
tap
использования , мы сможем найти некоторые интересные применения. Ниже приведены несколько пунктов (не исчерпывающий список), которые дадут нам несколько идей о том, как их использовать:Добавить элемент в массив на основе определенных условий
Инициализация массива и его возврат
Как синтаксический сахар , чтобы сделать код более читаемым - Можно сказать, что в приведенном ниже пример, использование переменных
hash
иserver
делает цель коды четкой.Инициализировать / вызывать методы для вновь созданных объектов.
Ниже пример из тестового файла
Чтобы действовать в соответствии с результатом
yield
вызова без использования временной переменной.источник
Вариант ответа @awa:
Как уже отмечалось, использование
tap
помогает выяснить назначение вашего кода (хотя и не обязательно делает его более компактным).Следующие две функции имеют одинаковую длину, но в первой вам нужно прочитать до конца, чтобы понять, почему я инициализировал пустой хеш в начале.
Здесь, с другой стороны, вы с самого начала знаете, что инициализируемый хеш будет выходом блока (и, в данном случае, возвращаемым значением функции).
источник
tap
дает более веский аргумент. Я согласен с другими, что когда вы видитеuser = User.new
, намерение уже ясно. Однако анонимная структура данных может использоваться для чего угодно, иtap
метод, по крайней мере, дает понять, что структура данных является фокусом метода.def tapping1; {one: 1, two: 2}; end
с использованием шоу.tap
в этом случае примерно на 50% медленнееЭто помощник для цепочки вызовов. Он передает свой объект в данный блок и после завершения блока возвращает объект:
Преимущество заключается в том, что tap всегда возвращает объект, к которому он был вызван, даже если блок возвращает какой-то другой результат. Таким образом, вы можете вставить блок отвода в середину существующего конвейера метода, не прерывая поток.
источник
Я бы сказал, что пользы от использования нет
tap
. Единственное потенциальное преимущество, как указывает @sawa, - цитирую я: «Читателю не нужно читать то, что находится внутри блока, чтобы знать, что создан пользователь экземпляра». Однако в этот момент можно привести аргумент, что если вы используете неупростую логику создания записи, ваше намерение будет лучше передано путем извлечения этой логики в отдельный метод.Я придерживаюсь мнения, что
tap
это ненужное бремя для читабельности кода, и его можно было бы обойтись без или заменить более совершенным методом, например методом извлечения. .Хотя
tap
это удобный метод, это также личные предпочтения. Дайтеtap
попробовать. Затем напишите код, не используя касание, и посмотрите, нравится ли вам один способ лучше другого.источник
Может быть множество применений и мест, где мы сможем их использовать
tap
. Пока я нашел только следующие 2 использованияtap
.1) Основная цель этого метода - подключиться к цепочке методов для выполнения операций с промежуточными результатами в цепочке. т.е.
2) Вы когда-нибудь вызывали метод для какого-то объекта, а возвращаемое значение не соответствовало вашим ожиданиям? Возможно, вы хотели добавить произвольное значение к набору параметров, хранящемуся в хэше. Вы обновляете его с помощью Hash. [] , Но вы получаете полосу возврата вместо хэша params, поэтому вы должны вернуть его явно. т.е.
Чтобы преодолеть эту ситуацию здесь,
tap
в игру вступает метод. Просто вызовите его на объекте, затем передайте касание блока с кодом, который вы хотите запустить. Объект будет передан блоку, а затем будет возвращен. т.е.Есть десятки других вариантов использования, попробуйте найти их сами :)
Источник:
1) API Dock Object Tap
2) пять рубиновых методов, которые вы должны использовать
источник
Вы правы: использование
tap
в вашем примере бессмысленно и, вероятно, менее чисто, чем ваши альтернативы.Как отмечает Ребицеле,
tap
это всего лишь удобный метод, часто используемый для создания более короткой ссылки на текущий объект.Один хороший вариант использования
tap
- отладка: вы можете изменить объект, распечатать текущее состояние, а затем продолжить изменение объекта в том же блоке. См., Например, здесь: http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions .Иногда мне нравится использовать
tap
внутренние методы для условного возврата раньше, в противном случае возвращая текущий объект.источник
Существует инструмент под названием flog, который измеряет, насколько сложно прочитать метод. «Чем выше оценка, тем труднее код».
и, судя по результату, метод с
tap
наиболее трудным для чтения (и я согласен с этим)источник
Вы можете сделать свои коды более модульными, используя tap, и добиться лучшего управления локальными переменными. Например, в следующем коде вам не нужно назначать локальную переменную вновь созданному объекту в области действия метода. Обратите внимание, что переменная блока u ограничена рамками блока. На самом деле это одна из прелестей кода Ruby.
источник
В рельсах мы можем
tap
явно использовать для белого списка параметров:источник
Приведу другой пример, который я использовал. У меня есть метод user_params, который возвращает параметры, необходимые для сохранения для пользователя (это проект Rails)
Вы можете видеть, что я ничего не возвращаю, но ruby возвращает результат последней строки.
Затем, через какое-то время, мне нужно было условно добавить новый атрибут. Итак, я изменил это примерно так:
Здесь мы можем использовать кран, чтобы удалить локальную переменную и удалить возврат:
источник
В мире, где шаблон функционального программирования становится лучшей практикой ( https://maryrosecook.com/blog/post/a-practical-introduction-to-functional-programming ), вы действительно можете видеть
tap
, какmap
на одном значении , чтобы изменить ваши данные в цепочке преобразований.Здесь не нужно заявлять
item
несколько раз.источник
В чем разница?
Разница в удобочитаемости кода чисто стилистическая.
Прохождение кода:
Ключевые моменты:
u
переменная теперь используется как параметр блока?user
переменная теперь должна указывать на пользователя (с именем пользователя: 'foobar', который также сохраняется).Документация по API
Вот легкая для чтения версия исходного кода:
Для получения дополнительной информации перейдите по этим ссылкам:
https://apidock.com/ruby/Object/tap
http://ruby-doc.org/core-2.2.3/Object.html#method-i-tap
источник