Crystal Lang 中的“&-=”运算符是什么?
What is the "&-=" operator in Crystal Lang?
我刚刚了解到 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
拼图的第一步是要认识到 a &-= b
只是 a = a &- b
的语法糖。或者更一般地说,a op= b
是 a = a op b
的语法糖。语言参考在 Operators.
中的 "Combined assignments" 下对此进行了详细说明
现在我们要问什么是 &-
,它与 -
有何不同?不幸的是,API 文档在这方面写得非常安静。语言参考也不是很详细,但在与上面相同的 Operators 页面上我们可以找到:
-
subtraction
&-
wrapping subtraction
那么什么是环绕减法?好吧,Crystal 具有固定大小的数字类型。所以在这种情况下它们可能会溢出或下溢。那是什么意思?让我们举个例子:
# 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?
所以程序试图低于 0
,UInt32
类型无法表示。它下流了。如果 Crystal 不做这个检查,CPU 会愉快地环绕整数类型,我们会在 items_left
(UInt32::MAX
) 中得到 4294967295
。
但有时,在低级代码中,这种行为正是我们想要的。例如,如果我们正在计算一些统计数据,比如发送的数据包,如果计数器溢出或下溢,我们不希望程序在这种情况下失败,回绕是可以的。或者,也许我们有一些性能敏感的代码,并且确定它的行为正确并且永远不会溢出,所以我们不想支付额外的 CPU 周期来检查操作是否刚刚溢出。
对于这些情况,有 &
前缀的数学运算符。它们只是简单地执行操作而不进行任何溢出检查。如果我们在上面的示例中使用 &-
而不是 -
,那么现在 items_left
中就会有 4294967295
。
一般来说,如果您需要包装运算符或从中受益,您就会知道。有疑问就当它们不存在吧。
我刚刚了解到 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
拼图的第一步是要认识到 a &-= b
只是 a = a &- b
的语法糖。或者更一般地说,a op= b
是 a = a op b
的语法糖。语言参考在 Operators.
现在我们要问什么是 &-
,它与 -
有何不同?不幸的是,API 文档在这方面写得非常安静。语言参考也不是很详细,但在与上面相同的 Operators 页面上我们可以找到:
-
subtraction
&-
wrapping subtraction
那么什么是环绕减法?好吧,Crystal 具有固定大小的数字类型。所以在这种情况下它们可能会溢出或下溢。那是什么意思?让我们举个例子:
# 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?
所以程序试图低于 0
,UInt32
类型无法表示。它下流了。如果 Crystal 不做这个检查,CPU 会愉快地环绕整数类型,我们会在 items_left
(UInt32::MAX
) 中得到 4294967295
。
但有时,在低级代码中,这种行为正是我们想要的。例如,如果我们正在计算一些统计数据,比如发送的数据包,如果计数器溢出或下溢,我们不希望程序在这种情况下失败,回绕是可以的。或者,也许我们有一些性能敏感的代码,并且确定它的行为正确并且永远不会溢出,所以我们不想支付额外的 CPU 周期来检查操作是否刚刚溢出。
对于这些情况,有 &
前缀的数学运算符。它们只是简单地执行操作而不进行任何溢出检查。如果我们在上面的示例中使用 &-
而不是 -
,那么现在 items_left
中就会有 4294967295
。
一般来说,如果您需要包装运算符或从中受益,您就会知道。有疑问就当它们不存在吧。