Меня интересует использование динамических (в отличие от лексических) переменных в Ruby.
Кажется, что нет прямого встроенного способа, как с let
в Лиспе. Кристиан Нойкирхен предлагает один из возможных способов создания динамической переменной области действия.Он создает «локальный хэш потока» в своем классе Dynamic
.Я не был в восторге от этого.
Тогда я вспомнил, что в Ruby 1.9 есть метод tap
.Я вижу много людей, использующих tap
для печати значений отладки в цепочке команд.Я думаю, что это может быть использовано для имитации динамически изменяемой переменной.
Ниже приведен пример ситуации, в которой нужно использовать динамическую переменную с ограничением, и решение с использованием tap
.
Если бы у меня был блог, чтобы опубликовать это и получить отзывы, я бы сделал это там.Вместо этого я прихожу в S / O за критику этой идеи.Опубликуйте критику, и я дам правильный ответ тому, у кого больше голосов.
Ситуация
У вас есть объект ActiveRecord, представляющий Account
, каждая учетная запись has_many
Transaction
с.A Transaction
имеет два атрибута:
Вы хотите найти сумму всех transactions
наaccount
, имея в виду, что amount
может быть либо nil
, либо Float
(нет, вы не можете критиковать это).
Ваша первая идея:
def account_value
transactions.inject(0){|acum, t| acum += t.amount}
end
Это бомбы, когда вы получаете нулевое количество в первый раз:
TypeError: nil can't be coerced into Fixnum
Чистый раствор
Используйте tap
для временного определения amount = 0
.Мы хотим, чтобы это было временным только в том случае, если мы забыли установить его обратно и сохранить transaction
с сохранением значения 0.
def account_value
transactions.inject(0){|acm, t| t.amount.tap{|amount| amount ||=0; acm+=amount}; acm}
end
Поскольку значение присваивания равно нулю, если нольamount
находится в пределах tap
, нам не нужно беспокоиться о том, чтобы забыть установить его на nil
.
Что вы думаете?