Подтвердить что ты не робот

Ruby boolean соглашение о двойном отрицании

Может кто-нибудь сказать мне, почему много булевых методов Ruby используют это соглашение о двойном отрицании?

!!(boolean expression)
4b9b3361

Ответ 1

Двойное отрицание гарантирует, что независимо от начального значения вы всегда будете получать true или false, а не какое-то значение тайны.

Это удобно, потому что он избегает оборванных ссылок на объекты, которые вам больше не нужны, или для того, чтобы различать два типа ложных значений, nil и false.

Часто вы увидите методы, написанные следующим образом:

def logged_in?
  [email protected]_user
end

Это вернет true или false, и это значение может быть использовано для любой цели. Сравните это с этим:

def logged_in?
  @session_user
end

В этом случае, если вы сохраните значение, вы фактически сохраняете весь объект @session_user, который может быть довольно значительным фрагментом памяти. Эта память не может быть выпущена до тех пор, пока ваша ссылка на нее не выйдет из сферы действия. Поскольку существует только один true и один false, нет необходимости в сборке мусора.

Ответ 2

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

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, если это не так.

Ответ 3

По-моему, Ruby просто слишком умен по поводу Booleans. Это обходное решение для случаев, когда умность вызывает проблемы.

Здесь чрезмерная уловка: нет булевского класса. Вместо этого существует соглашение, согласно которому любое значение может служить логическим. В контексте, где требуется истинное или ложное значение, nil или false означает "false", а что-то еще означает "true". Значения true и false не являются частью специального класса, они являются единственными членами их соответствующих классов — они существуют только для того, чтобы сделать код более удобным для чтения.

Я предполагаю, что это отлично работает в большинстве случаев, но каждый раз в течение очень долгого времени вам нужно булево значение, которое всегда true или false. Например, мне недавно нужно было сравнить два булевых значения и сделать что-то особенное, если они были разными; единственной проблемой было то, что один из них был либо true, либо false, а другой был либо 1, либо nil. Фикс? Используйте тот факт, что !!nil == false и !!1 == true.