去扫描仪 - 空白的正确性?

时间:2014-03-16 14:50:46

标签: go

text/scanner/scanner.go中的Go扫描程序包使用技巧来查找空格:

const GoWhitespace = 1<<'\t' | 1<<'\n' | 1<<'\r' | 1<<' '

然后:

// skip white space
for s.Whitespace&(1<<uint(ch)) != 0 {
    ch = s.next()
}

由于字符值向左移动超过31,是否会出现不唯一的情况?我的意思是,当一些char与tab modulo 32相同时,它会被识别为空格?

2 个答案:

答案 0 :(得分:2)

如上所述in the spec<<是一个轮班操作:

  

移位运算符将左操作数移位右操作数指定的移位计数。如果左操作数是有符号整数,则它们实现算术移位;如果是无符号整数,则它们实现逻辑移位。班次计数没有上限。对于移位计数n,移位的行为就好像左操作数被移位n次1。结果,x <&lt;&lt; 1与x * 2和x>&gt;相同。 1与x / 2相同但截断为负无穷大。

对于ch的大值,1<<uint(ch)cause an overflow

  

对于无符号整数值,操作+, - ,*和&lt;&lt;计算模2 n ,其中n是无符号整数类型的位宽。松散地说,这些无符号整数运算在溢出时丢弃高位,程序可能依赖于“环绕”。

     

对于有符号整数,操作+, - ,*和&lt;&lt;可能合法地溢出并且结果值存在并且由有符号整数表示,操作及其操作数确定性地定义。溢出不会引发异常。在假设不发生溢出的情况下,编译器可能不会优化代码。例如,它可能不假设x < x + 1始终为真。

因此,使用按位旋转运算符(您似乎在描述的内容)实现<<会违反规范。对于大于1<<uint(ch)类型大小的ch值,int将评估为零,因此不会导致任何误报。

答案 1 :(得分:0)

完全回答:

Spec明确说明对于无符号运算,我们将高位掩盖掉,这样低位实际上是“环绕”。

它起作用的原因是:

  1. Scanner.Whitespace实际上是uint64,因此GoWhitespace的值完全符合
  2. 运行时对无符号整数的操作s.Whitespace&(1<<uint(ch))可以具有任意大的中间值并且将环绕。因此,如果说char是“a”(96),我们有1 << 96溢出,因此模数大小为64位int为0。