数组访问的奇怪上限

Weird ceilling for array access

我在使用数组索引器时在 PowerShell 中遇到了奇怪的代码片段。为什么您认为它会以下列方式运行?

我期望的标准行为是每次都获取数组的确切成员,在本例中首先是从零开始

(0, 1)[0] == 0          # as expected
(0, 1 -ne 2)[0] == 0    # as expected regardless second member would be casted from bool to int
(0, 1 -ne 0)[0] == 1    # magic starts here

到目前为止,我希望它是将 1 -ne 0 从 bool 转换为 int 的结果,并与数组第一位的 0 一起形成已知的异常,但是:

(0, 60 -ne 0)[0] == 60   # ignores first member and whole (-ne 0) part
(0, 60 -ne 1)[0] == 0    # as expected
(1, 60 -ne 0)[0] == 1    # as expected

在这一点上,它似乎只有在第一个成员是 0 时才会生效,而不管它作为变量传递,第二部分必须正好是 1 -ne 0

# doesn't matter if first member is variable    
$x = 0
($x, 1 -ne 0)[0] == 1       # same magic as before
($x, 0 -ne 1)[0] == 0       # as expected by may be caused by leading zero of 0 -ne 1
($x, 0 -ne 0)[0] == null    # this is also very weird
($x, 1 -ne 1)[0] == 0       # maybe return of bool comparison or simply first member, I would expect null as before

我知道,只要防止代码在数组中混合 bool 和 int,就可以解决所有关于这些事情的疑惑。 我如何发现它在我们的遗留代码中用作天花板

return ([int]$lastResultCode, 1 -ne 0)

而不是:

if ($lastResultCode == 0) return 1
else return $lastResultCode

但请考虑此代码已经发布的情况,无法更改此代码,而且该机器上可能是 PowerShell 版本的升级,因此可能会更改未来的行为。对于这种情况,我想请您就导致这种行为的原因提出意见。

这里发生了两件事:

  1. , 运算符的优先级高于比较运算符。所以,像这样的表达式:

    (0, 1 -ne 0)[0]
    

    实际解析为:

    ((0, 1) -ne 0)[0]
    

    您可以在 about_Operator_Precedence.

  2. 下阅读有关 PowerShell 运算符优先级的更多信息
  3. PowerShell 比较运算符可用于标量(单个项目)和数组。当您将它们与数组一起使用时,它们将 return 所有满足条件的项目:

    PS > (4, 5, 3, 1, 2) -gt 2  # All items greater than 2
    4
    5
    3
    PS > (4, 5, 3, 1, 2) -ne 3  # All items that do not equal 3
    4
    5
    1
    2
    PS >
    

考虑到这些要点,您所看到的行为就很容易解释了。表达式:

(0, 1 -ne 0)[0]

首先解析为:

((0, 1) -ne 0)[0]

然后变成:

(1)[0]

因为 -ne return 来自 (0, 1) 的项目不等于 0,也就是 1.


解决方法就是多加一组括号:

(0, (1 -ne 0))[0]

这将导致 PowerShell 首先评估 1 -ne 0 部分并按您预期的方式运行:

PS > (0, (1 -ne 0))
0
True
PS > (0, (1 -ne 0))[0]
0
PS >