Swift 中 &<< 和 << 运算符有什么区别?

Dmi*_*try 1 bit-manipulation operators bit swift

Swift 中 &<< 和 << 运算符有什么区别?似乎它们返回相同的结果:

print(2 << 3) // 16
print(2 &<< 3) // 16
Run Code Online (Sandbox Code Playgroud)

Mar*_*n R 5

FixedWithInteger协议将“屏蔽左移运算符”定义&<<

返回将值的二进制表示向左移位指定位数的结果,将移位量屏蔽为类型的位宽。

&<<当您需要执行移位并确保移位量在范围内时,请使用屏蔽左移运算符 ( ) 0..<lhs.bitWidth。在移位之前,屏蔽左移位运算符将移位屏蔽到此范围。使用此屏蔽值执行移位。

因此,如果移位量大于或等于左操作数的位宽,结果可能会有所不同: 示例:

print(2 << 70) // 0
print(2 &<< 70) // 128
Run Code Online (Sandbox Code Playgroud)

这里的移位量 (70) 大于Int(64) 的位,因此2 << 70计算结果为零。在第二行中,数字向左移动了 70% 64 = 6 位。

还有一个类似的“屏蔽右移运算符” &>>。例子:

let x = Int8.min        // -128 = 0b10000000
print(Int8.min >> 8)    //   -1 = 0b11111111
print(Int8.min &>> 8)   // -128 = 0b10000000
Run Code Online (Sandbox Code Playgroud)

这里的第一个结果是-1因为将有符号整数右移会用符号位填充左侧的空位置第二个结果是-128因为移位量为零:8 % 8 = 0

SR-6749 中还描述了命名和预期用途:

然而,操作符的目标是永远不会发生这种包装行为——当你知道你的移位量是 <= 位宽的静态知识时,你会使用它。通过屏蔽,您和编译器可以同意不需要分支,因此您可以在没有零分支和零风险的未定义行为(负或太大的转变)的情况下获得稍快的代码。

文档令人困惑,因为它们给出了一个我认为没有人会故意编写的示例——依靠包装行为来使用一些超出范围的值作为移位量。

因此,使用屏蔽移位运算符可以提高性能。许多示例可以在 Swift 标准库的源代码中找到,例如在UTF8.swift 中