我刚刚知道有 &-=
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
. 语文参考资料在 "联合转让 "中对此作了详细说明。操作人员.
现在我们要问的是 &-
又与 -
? 遗憾的是,在写这篇文章的时候,API文档对此还很平静。语言参考也不是很详细,但是在上面的操作符页面我们可以找到。
-
减法&-
包干减法
那么什么是包装减法呢?嗯,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就会很高兴地在整数类型上绕来绕去,我们就可以得到 4294967295
在 items_left
(UInt32::MAX
).
但有时,在低级代码中,这种行为是我们想要的。比如说如果我们在统计一些统计数据,比如说发送的数据包,如果这个计数器溢出或不足,在这种情况下,我们不希望程序失败,绕过就可以了。或者我们有一些对性能敏感的代码,确信它的行为是正确的,永远不会溢出,所以我们不想在检查操作是否刚刚溢出上付出额外的CPU周期。
对于这些情况,我们可以使用 &
前缀的数学运算符。它们只是简单地执行操作,而没有任何溢出检查。如果我们使用 &-
而不是 -
在上面的例子中,我们会有 4294967295
在 items_left
现在。
在一般情况下,你知道万一你需要或有好处的包装运营商。如果有疑问,就当它们不存在。