我正在尝试制作一个动态大小的锯齿状数组来表示一个非常简单的控制台游戏的游戏网格。
# Determine the size of the board. Enforce the size so as to not make it too large.
$boardSize = 5
# Game board characters
[char]$bushCharacter = "#"
# Initialize Game board object
$gameBoard = ,(@($bushCharacter) * $boardSize) * $boardSize
如果我要在屏幕上打印它,那就是想法。我会得到像我这样的东西。
0..($boardSize - 1) | ForEach-Object{$gameBoard[$_] -join ""}
#####
#####
#####
#####
#####
一切顺利,直到我尝试对单个项目进行更改:$gameBoard[0][1] = "F"
。我重新打印网格的预期结果是
#F###
#####
#####
#####
#####
我的实际输出是:
#F###
#F###
#F###
#F###
#F###
这告诉我,我创建的数组所有行都引用了彼此。为什么此代码不会创建单独的唯一数组?我可以做些什么改变才能使它发挥作用。我知道其他方法可以像+=
一样使用索引循环,但我认为这种方法更好。
答案 0 :(得分:2)
如果您查看乘法运算符(*
)的文档,您会发现(来自about_Arithmetic_Operators
):
* Multiplies integers; copies strings 6*2
and arrays the specified number of "w" * 3
times.
请注意 副本 一词。
现在看一下备注部分下的.NET Array.Copy()
method的MSDN文档:
如果 sourceArray 和 destinationArray 都是引用类型数组或者都是Object类型的数组,执行浅拷贝。数组的浅表副本是一个新数组,包含与原始数组相同元素的引用。不复制元素本身或元素引用的任何内容。相反,Array的深层副本会复制元素以及元素直接或间接引用的所有内容。
假设数组乘法运算符总是产生相同类型的数组是公平的 - 即。无论是引用类型数组还是Object数组(无论是什么) - 这基本上就是你看到的效果。
我会这样做:
$gameBoard = 1..$boardSize |ForEach-Object { ,@(@($bushCharacter) * $boardSize) }
答案 1 :(得分:2)
Array
是一个reference type,因此你只是在复制(复制)引用/指针而不是内容本身。
解决方法:创建一个循环以生成唯一数组。
$gameBoard = 0..($boardSize - 1) | ForEach-Object{ ,(@($bushCharacter) * $boardSize) }
您可以使用以下方法验证(没有文档)对象是引用类型:
Add-Type -AssemblyName "Microsoft.VisualBasic"
[Microsoft.VisualBasic.Information]::IsReference($gameBoard[0])
True
#or as mentioned by Mathias
-not $gameBoard[0].GetType().IsValueType
True