Главная > Powershell > Копирование и клонирование массивов в Powershell

Копирование и клонирование массивов в Powershell

Сегодня поговорим о некоторых особенностях копирования массивов в Powershell, а также постараемся разобраться чем отличается операция копирования от клонирования.

Когда мы копируем массив через оператор присваивания, на самом деле мы копируем ссылку на область памяти, но не само содержимое переменной. Т.е. при таком способе копирования при изменении второго (дочернего) массива, исходный массив также будет изменён.

В этом легко убедиться на примере:

$a = 1..10
$b = $a
$b[5] = 'Значение изменено'

Хоть мы и изменяли массив, находящийся в переменной $b, массив $a также был изменён, так как обе переменные ссылаются на одну область памяти:

PS C:\> $b[5]
Значение изменено
PS C:\> $a[5]
Значение изменено

Для того, чтобы “по честному” скопировать массив его нужно клонировать, используя метод Clone():

$a = 1..10
$b = $a.Clone()

Теперь если мы изменим массив $b, массив $a останется нетронутым:

$b[5] = 'Значение изменено'

PS C:\> $b[5]
Значение изменено

PS C:\> $a[5]
6

Таким образом использование метода Clone() позволяет скопировать содержимое массива в новый массив.

Однако, если элементами массива были не простые типы данных (такие как числа, или строки), а объекты (например, хэш-таблицы), при клонировании массива сохраняется область памяти с этими объектами, поэтому метод Clone() создаст новый массив, но этот новый массив будет ссылаться на те же самые объекты. Посмотрим на примере:

$Object1 = @{Name = 'Иванов'; Id = 1}
$Object2 = @{Name = 'Петров'; Id = 5}

$a = $Object1, $Object2
$b = $a.Clone()

$b[0].Name = 'Значение изменено'

PS C:\> $b[0].Name
Значение изменено

PS C:\> $a[0].Name
Значение изменено

Несмотря на то, что мы клонировали массив, новый массив всё ещё ссылается на те же объекты (из первого массива), и изменение объектов в одном массиве на самом деле затронет оба наших массива.

В этом случае можно изменить только сами элементы массива, а не объекты, находящиеся в нём:

$Object1 = @{Name = 'Иванов'; Id = 1}
$Object2 = @{Name = 'Петров'; Id = 5}

$a = $Object1, $Object2
$b = $a.Clone()

$b[0] = 'Значение изменено'

PS C:\> $b[0]
Значение изменено

PS C:\> $a[0]
Name                           Value                                                                                     
----                           -----                                                                                     
Id                             1                                                                                         
Name                           Иванов 

Поэтому, если нужно чтобы была копия такого массива, лучше подумать об этом заранее, и в момент создания сделать два одинаковых массива.

На самом деле всё-же существует лайфхак и для такого случая: в момент копирования массива его можно конвертировать в JSON-объект, и сразу же обратно:

$Object1 = @{Name = 'Иванов'; Id = 1}
$Object2 = @{Name = 'Петров'; Id = 5}

$a = $Object1, $Object2

$b = $a | ConvertTo-Json | ConvertFrom-Json

$b[0].Name = 'Значение изменено'

PS C:\> $b[0].Name
Значение изменено

PS C:\> $a[0].Name
Иванов

Как видим мы получили два независимых массива.

Следует иметь в виду, что при таком способе копирования изменяется тип скопированного объекта:

PS C:\> $a[0].GetType().FullName
System.Collections.Hashtable

PS C:\> $b[0].GetType().FullName
System.Management.Automation.PSCustomObject
Реклама
Рубрики:Powershell Метки:
  1. Комментариев нет.
  1. No trackbacks yet.

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: