In PowerShell, everytime I execute the script the array gets bigger

╄→гoц情女王★ 提交于 2021-02-18 19:11:28

问题


So I'm starting with PowerShell and this is odd to me. I put a breakpoint in the last line and when I run the script $newArray is "abc" then it pauses in Write-Output and I stop the debugger. If I run it again, $newArray is "abcabc" and so on. For one, I think I'm doing something wrong as this behavior is so weird to me, like it stores in memory despite of stopping the debugger. And secondly I would expect $newArray to be an array and not a single string with the values concatenated. Any clues?

$array = "a", "b", "c";
$newArray;
foreach ($item in $array )
{
    $newArray += $item
}
Write-Output "Just before ending script";

回答1:


tl;dr

  • In order to use += to iteratively build up an array, you must (re)initialize the target variable as an empty array: $newArray = @(); see the bottom section for what happens if you don't.

    • Re repeated debugging passes: unfortunately, both the obsolescent Windows PowerShell ISE and the PowerShell extension for Visual Studio Code run in the same session, so that subsequent invocations can be affected by the state of previous ones. However, the Visual Studio PowerShell extension can be configured to use a new session every time - see this answer.
  • That said, it's usually better not to use +=, because it is inefficient: it requires creating a new array behind the scenes in every iteration, because .NET arrays are immutable data structures (in terms of element count).

    • In your simple case, you could simply use the following to create a (shallow) copy of $array, via @(), the array-subexpression operator, which implicitly clones an array:
      • $newArray = @($array)
    • If you need to perform an operation on each element of the source array, you can take advantage of the fact that you can use a foreach loop as an expression, which implicitly collects the iterations' outputs in an array - assuming that there's more than one output:
      • [array] $newArray = foreach ($item in $array) { $item + '!' }
      • Note the [array] type constraint, which ensures that $newArray receives an array even if the foreach loop happens to output just one object; alternatively, you could have wrapped the loop into @(...)

How += works:

In short: if the first value you add to an uninitialized variable with += is a string, that string is stored as-is, and all subsequent += operations perform string concatenation; specifically:

  • $newArray += $item is syntactic sugar for $newArray = $newArray + $item.

  • If $newArray has not been defined, its implied value is $null[1]

  • Since your $item values are strings ([string]), $newArray += $item in the first iteration amounts to $newArray = $null + "a", which assigns "a" - a single string - to $newArray (with a [string] RHS, $null on the LHS is treated like an empty string, performing string concatenation that effectively returns the RHS string in this case).

  • The second iteration amounts to $newArray = "a" + "b", which - given that the LHS is a string - again performs string concatenation, so that $newArray contains "ab" afterwards.

  • The third (and any hypothetical subsequent iterations) simply keep appending to the string stored in $newArray.

Generally speaking:

  • In the first += iteration of $initiallyUninitialized += <value>, $null + <value> is evaluated, which stores <value> in $initiallyUninitialized and effectively types it as whatever type <value> happens to be.

  • In subsequent += iterations, the then-current type of the $initiallyUninitialized value determines the result of the implied $initiallyUninitialized + <value> operation - which typically, but not necessarily, preserves that type:

    • The type may automatically widen in the case of a numeric type:
      • $a += [int]::MaxValue; $a += [int]::MaxValue - $a is now of type [double].
    • The operation may fail with a statement-terminating error if the + operation cannot be performed:
      • $a += Get-Date; $a += Get-Date - causes a statement-terminating error, because two [datetime] instances cannot be added (+).

[1] This applies by default (Set-StrictMode -Off); with Set-StrictMode -Version 1 or higher, you'd actually get a statement-terminating error.




回答2:


Setting an array's value to @() will clear it

Example: Add $newArray = @(); to the end of the script

Do you want it to keep the full list in one of the arrays or do you want it cleared every time you run it?



来源:https://stackoverflow.com/questions/63661810/in-powershell-everytime-i-execute-the-script-the-array-gets-bigger

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!