Что такое оператор & & = = в Crystal Lang? - PullRequest
1 голос
/ 26 апреля 2020

Я только что узнал о существовании &-= оператора в Crystal. Что он делает?

Вот пример из Mutex # try_lock :

private def try_lock
  i = 1000
  while @state.swap(1) != 0
    while @state.get != 0
      Intrinsics.pause
      i &-= 1
      return false if i == 0
    end
  end

  true
end

Во время попытки я не вижу никакой разницы со знакомым -= оператор. Например, эти два фрагмента дают одинаковый результат:

i = 1000
while i != 0
  puts i
  i -= 1
end
i = 1000
while i != 0
  puts i
  i &-= 1
end

1 Ответ

5 голосов
/ 26 апреля 2020

Первая часть головоломки - понять, что a &-= b - это просто синтаксический сахар для a = a &- b. Или, в общем, a op= b - это синтаксический сахар для a = a op b. Ссылка на язык подробно описывает это в разделе «Комбинированные назначения» в Операторы .

Теперь нам нужно спросить, что такое &- и чем оно отличается от -? К сожалению, API-документы на момент написания очень тихо об этом. Справочник по языку также не очень сложен, но на той же странице Операторы, что и выше, мы можем найти:

- вычитание &- вычитание переноса

Так что же такое вычитание переноса? Ну, у Кристалла есть фиксированные размеры чисел. Таким образом, они могут переполниться или потеряться в этом случае. Что это обозначает? Давайте рассмотрим пример:

# We have something to sell! Let's keep track of how many!
# It doesn't really make sense to have negative something left,
# so an unsigned integer ought to this.
items_left = 2u32

# Just made the first sell! Let's remember
items_left -= 1

# People seem to actually like this
items_left -= 1

# I could do this all day!
items_left -= 1 # => Unhandled exception: Arithmetic overflow (OverflowError)

# Oh no what happend?

Итак, программа попыталась на go ниже 0, что тип UInt32 не может представлять. Это снизилось. Если Crystal не выполнит эту проверку, процессор с радостью обернется целочисленным типом, и мы получим 4294967295 in items_left (UInt32::MAX).

Но иногда, в коде низкого уровня, это поведение то, что мы хотим. Например, если мы подсчитываем некоторую статистику c, скажем, отправленные пакеты, если этот счетчик переполнен или переполнен, мы не хотим, чтобы в этом случае произошел сбой программы, обертывание - это нормально. Или, может быть, у нас есть некоторый чувствительный к производительности код, и мы уверены, что он работает правильно и никогда не будет переполнен, поэтому мы не хотим платить дополнительные циклы ЦП, проверяя, не переполнилась ли операция.

Для этих случаев есть математические операторы с префиксом &. Они просто выполняют операцию без какой-либо проверки переполнения. Если бы мы использовали &- вместо - в приведенном выше примере, у нас было бы 4294967295 в items_left сейчас.

В общем, вы знаете, если вам нужны операторы переноса или вы получаете выгоду , Сомневаешься, просто притворись, что их не существует.

...