Может кто-нибудь сказать мне, почему много булевых методов Ruby используют это соглашение о двойном отрицании?
!!(boolean expression)
Может кто-нибудь сказать мне, почему много булевых методов Ruby используют это соглашение о двойном отрицании?
!!(boolean expression)
Двойное отрицание гарантирует, что независимо от начального значения вы всегда будете получать true
или false
, а не какое-то значение тайны.
Это удобно, потому что он избегает оборванных ссылок на объекты, которые вам больше не нужны, или для того, чтобы различать два типа ложных значений, nil
и false
.
Часто вы увидите методы, написанные следующим образом:
def logged_in?
[email protected]_user
end
Это вернет true
или false
, и это значение может быть использовано для любой цели. Сравните это с этим:
def logged_in?
@session_user
end
В этом случае, если вы сохраните значение, вы фактически сохраняете весь объект @session_user
, который может быть довольно значительным фрагментом памяти. Эта память не может быть выпущена до тех пор, пока ваша ссылка на нее не выйдет из сферы действия. Поскольку существует только один true
и один false
, нет необходимости в сборке мусора.
Предположим, вы хотите определить метод, возвращающий логическое значение. Например, соответствует ли строка регулярному выражению.
class String
def include? regex; self =~ regex end
end
Если вы выполните вышеописанное, оно вернет nil
, если оно не соответствует, и целое число, когда оно совпадает. Во многих случаях это не имеет большого значения (nil
похож на false
, а true
можно заменить на целое число). Но если вы действительно хотите иметь значение boolean как возвращаемое значение, если вы делаете
class String
def include? regex; !!(self =~ regex) end
end
он вернет true
, когда он будет соответствовать, false
, если это не так.
По-моему, Ruby просто слишком умен по поводу Booleans. Это обходное решение для случаев, когда умность вызывает проблемы.
Здесь чрезмерная уловка: нет булевского класса. Вместо этого существует соглашение, согласно которому любое значение может служить логическим. В контексте, где требуется истинное или ложное значение, nil
или false
означает "false", а что-то еще означает "true". Значения true
и false
не являются частью специального класса, они являются единственными членами их соответствующих классов — они существуют только для того, чтобы сделать код более удобным для чтения.
Я предполагаю, что это отлично работает в большинстве случаев, но каждый раз в течение очень долгого времени вам нужно булево значение, которое всегда true
или false
. Например, мне недавно нужно было сравнить два булевых значения и сделать что-то особенное, если они были разными; единственной проблемой было то, что один из них был либо true
, либо false
, а другой был либо 1, либо nil
. Фикс? Используйте тот факт, что !!nil == false
и !!1 == true
.