Що робить !! означає в рубіні?


Відповіді:


161

Не так. Він використовується для перетворення значення в булеве:

!!nil   #=> false
!!"abc" #=> true
!!false #=> false

Це, як правило , немає необхідності використовувати хоча , так як тільки помилкові значення в рубін nilі false, тому , як правило , краще , щоб ця конвенція позиції.

Подумайте про це як

!(!some_val)

Одне, що легітимно використовується, це запобігання поверненню величезних фрагментів даних. Наприклад, ви, ймовірно, не хочете повертати 3MB даних зображень у своєму has_image?методі, або ви не хочете повертати весь logged_in?метод об'єкта користувача в методі. Використання !!перетворює ці об'єкти в простий true/ false.


8
Це не погана практика використовувати це. Подвійний чуб часто використовується в предикатах (способи, що закінчуються?), Щоб повернути явно булеве значення.
Swanand

6
Алекс, вам не потрібно турбуватися про повернення великих об’єктів, оскільки Рубі поверне посилання, а не копію об'єкта.
DSimon

10
@DSimon, іноді вам потрібно турбуватися про великі об'єкти, як, наприклад, під час друку або реєстрації значення під час налагодження.
Уейн Конрад

Чому б просто не повернутися .nil?замість використання !!? Чи є різниця?
ashes999

3
Існує різниця, коли ваша цінність є булевою. !!true #=> trueіtrue.nil? #=> false
Алекс Уейн

31

Він повертається, trueякщо об’єкта праворуч немає nilі немає false, falseякщо він є nilабоfalse

def logged_in?   
  !!@current_user
end

1
Це було очевидно, що це походить від Restful_Auth ?! : D
Камерон

14

!означає заперечення булевого стану, два !s - це не що інше, крім подвійного заперечення.

!true == false
# => true

Зазвичай він застосовується для примушування методу повернути булеву форму. Він виявить будь-який вид правдивості, такий як рядок, цілі числа і що ні, і перетворить його в булевий.

!"wtf"
# => false

!!"wtf"
# => true

Більш реальний випадок використання:

def title
  "I return a string."
end

def title_exists?
  !!title
end

Це корисно, коли ви хочете переконатися, що булева інформація повернута. IMHO - це начебто безглуздо, бачачи, що і те, if 'some string'і if trueте саме такий потік, але деяким людям вважається корисним явно повернути булеву форму.


мені здається, що це просто швидший спосіб, ніж використання оператора if або термінального оператора. Оскільки ви не можете просто повернутися title, може також зробити найближче до нього ... Я думаю
Карсон Майєрс,

6

Зауважте, що ця ідіома існує і в інших мовах програмування. C не мав внутрішнього boolтипу, тому всі булеві символи були набрані intнатомість із канонічними значеннями 0або 1. Візьмемо цей приклад (для чіткості додаються круглі дужки):

!(1234) == 0
!(0) == 1
!(!(1234)) == 1

Синтаксис "не-не" перетворює будь-яке ненульове ціле число 1в канонічне булеве справжнє значення.

В цілому, однак, я вважаю, що набагато краще порівняти порівняно, ніж використовувати цю незвичайну ідіому:

int x = 1234;
if (!!x); // wtf mate
if (x != 0); // obvious

Або просто якщо (x). !! корисно, коли вам потрібно отримати або 0/1. Ви можете чи не можете розглянути (x)? 1: 0 зрозуміліше.
дероберт

3

Це корисно, якщо вам потрібно зробити ексклюзив або . Копіювання відповіді Метта Ван Хорна з незначними змінами:

1 ^ true
TypeError: can't convert true into Integer

!!1 ^ !!true
=> false

Я використовував це для того, щоб дві змінні були або нульовими, або обома не нульовими.

raise "Inconsistency" if !!a ^ !!b

3

Це "подвійно-негативно", але практика відлякує. Якщо ви використовуєте rubocop , ви побачите, що він скаржиться на такий код із Style/DoubleNegationпорушенням.

В обґрунтування стану:

Оскільки це однозначно і зазвичай є зайвим, цього слід уникати [тоді перефразовуючи:] Змінити !!somethingна!something.nil?


1
Але ... !!false # => falseпоки!false.nil? # => true
Дуг

@Doug Якщо ви знаєте, що у вас булеве значення, воно зайве (просто використовуйте це значення). Якщо ви цього не зробите, ви можете використовувати !(foo.nil? || foo == false)- більш багатослівний, так, але менш дурний.
Девід Молес

0

Розуміння того, як це працює, може бути корисним, якщо вам потрібно перетворити, скажімо, перерахування в булеве. У мене є код, який робить саме це, використовуючи classy_enumдорогоцінний камінь:

class LinkStatus < ClassyEnum::Base
  def !
    return true
  end
end

class LinkStatus::No < LinkStatus
end

class LinkStatus::Claimed < LinkStatus
  def !
    return false
  end
end

class LinkStatus::Confirmed < LinkStatus
  def !
    return false
  end
end

class LinkStatus::Denied < LinkStatus
end

Потім у службовому коді я маю, наприклад:

raise Application::Error unless !!object.link_status   # => raises exception for "No" and "Denied" states.

Ефективно оператор bangbang став тим, що я б інакше написав як метод, який називається to_bool.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.