Метод 'tap' для объекта String не возвращает ожидаемый результат

Я столкнулся с интересной проблемой при использовании метода "tap" для объектов типа "String".

"abc".tap { |o| o = "xyz" } # this line returns "abc" instead of "xyz"

Метод "tap" работает с объектами других типов.

[].tap { |o| o << "xyz" } # this line returns ["xyz"] as expected

Я использую Rails 2.3.2 и Ruby 1.8.6 в Windows XP.

Что мне здесь не хватает?

Обновление 1: я решил эту проблему. Это была ошибка использования с моей стороны. В первом сценарии я повторно назначил значение блочному параметру вместо его изменения. Я смог переписать код и получить ожидаемый результат.

"abc".tap { |o| o.replace "xyz" }

Обновление 2: Используемый здесь код просто для демонстрации проблемы. Мой фактический код не выглядит так.

Ответ 1

Объект # tap всегда возвращает исходный объект, переданный ему после выполнения блока, даже если блок возвращает что-то другое.

Преимущество здесь в том, что вы можете поместить tap в середину цепочки и проверить значение объекта без изменения исходного значения.

Это означает, что если вы передадите "abc" в ответ, он выполнит блок и вернет "abc". Ваше назначение o не означает ничего из-за определения области. Аналогично, если вы передадите пустой массив в ответ, он вернет пустой массив обратно. Однако во втором примере вы изменили исходное значение. Операции, которые изменяют оригинал, такой как < или gsub! или аналогичным образом изменит объект до его возврата, поэтому вы получите другое значение назад.

Откажитесь от http://moonbase.rydia.net/mental/blog/programming/eavesdropping-on-expressions для более интересных примеров о том, как использовать кран. Не используйте его для назначения или модификации, иначе вы вернетесь в выигрышные результаты.

Обновление: для вашего редактирования, почему это решает проблему? Я не понимаю, почему вы вызываете tap, чтобы выполнить замену, когда вы можете просто вызвать replace на самом объекте. Какая польза от вас?