第一个难题是要意识到a &-= b 只是a = a &- b 的语法糖。或者更一般地说,a op= b 是a = a op b 的语法糖。语言参考在Operators 的“组合作业”下对此进行了详细说明。
现在我们需要问一下&- 是什么,它与- 有什么不同?不幸的是,API 文档在这方面写得很安静。语言参考也不是很详细,但是在与上面相同的 Operators 页面上我们可以找到:
-减法
&-换行减法
那么什么是换行减法?好吧,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。
一般来说,您知道是否需要或从包装运算符中受益。有疑问,就假装它们不存在。