PetSerAl предоставил критический указатель в кратком комментарии:
Разница в рендеринге сводится к тому, что:
- оператор
test
- это команда (вызов функции, командлета или внешней программы)
- , тогда как
$result
(который ранее захватывал выходные данные test
) является выражением (что-то, включающее только ссылки на переменные, операторы PowerShell и вызовы методов .NET, вне конвейер - хотя он может содержать вложенных команды).
Выводя , $results.ToArray()
из функции test
(функция является одной из форм команды), вы используете ,
, оператор построения массива, для переноса $results.ToArray()
(что приводит к массиву массивов) во вспомогательном, временном одноэлементном массиве, который является обычной техникой, гарантирующей, что коллекция передается как одиночный объект , а не перечисляется его элементов .
То есть aux. Массив-оболочка :
неизменно теряется при выводе в конвейер , из-за поведения автоматического развертывания (развертывания) конвейера,
, но гарантирует, что массив в оболочке будет рассматриваться как отдельный объект при следующей команде в конвейере .
Концептуально более четкий, но более подробный эквивалент , $results.ToArray()
внутри вашей функции - Write-Output -NoEnumerate $results.ToArray()
; то есть обычно неявный вывод PowerShell делается явным, с запросом на подавление поведения по умолчанию перечисления выходных коллекций.
Учитывая, что в конвейере нет дополнительной команды, вывод tests
неявно выводится на экран .
В данном случае печать массива массивов как одного объекта приводит к форматированию вывода списка свойств, которое вы видели.
Напротив, $result
, поскольку выражение равно , неявно пронумеровано . То есть массив массивов, захваченных из test
- без вспомогательного. массив обёрток! - отправляется один элемент за раз в систему форматирования вывода, и эти элементы затем визуализируются более осмысленно.
Чтобы предоставить более простой пример :
Предположим, что ваша функция test
использует return , , (1..3)
для вывода массива контейнера, содержащего массив из 3 элементов, который, наконец, обернут в aux. одноэлементный массив (как отступление: return
в PowerShell - это просто синтаксический сахар для выхода из блока функции или скрипта, он не имеет прямой связи с тем, что output ).
Выполнение функции test
эквивалентно прямому выполнению следующего выражения :
, , (1..3)
То есть внешнее, aux. массив снова отбрасывается из-за неявного перечисления, и , (1..3)
отображается как отдельный объект , что приводит к формату списка свойств:
Length : 3
LongLength : 3
Rank : 1
SyncRoot : {1, 2, 3}
IsReadOnly : False
IsFixedSize : True
IsSynchronized : False
Count : 3
Напротив, выполнение $result
(после запуска $result = test
) эквивалентно просто:
, (1..3)
То есть внешнее, aux. массив был потерян во время $result = test
, контейнерный массив теперь тоже неявно перечисляется, и (1..3)
как отдельный объект визуализируется более осмысленно (вы не можете визуально отличить его от отправки 1..3
непосредственно в конвейер, т.е. элемент):
1
2
3
Как отформатированы массивы для отображения
Когда команда или выражение не записываются в переменную, не отправляются в конвейер другой команде и не перенаправляются (с >
или >>
), они неявно выводятся на экран (хост) с использованием вывода PowerShell по умолчанию система форматирования.
Вы можете думать о такой команде, как:
test
эквивалент [1] :
test | Out-Host
Out-Host
автоматически выбирает командлет Format-*
, который будет использоваться для рендеринга, который подходит для ввода под рукой, на основе первого объекта ввода:Если этот объект имеет 4 или менее свойств, выбирается Format-Table
; в противном случае это Format-List
.
Однако, если этот первый входной объект является коллекцией (реализует IEnumerable
), именно первый элемент этой коллекции основан на выборе командлета форматирования (в отличие от к типу коллекции в целом), и элементы коллекции форматируются индивидуально с помощью этого командлета.
В случае, когда ваша переменная $result
получает выходные данные, первым элементом входного массива является экземпляр [pscustomobject]
(созданный с помощью New-Object PSObject
) со свойством 1, key1
; поэтому выбирается Format-Table
, а экземпляры [pscustomobject] `, составляющие массив, отображаются в табличном формате.
В отличие от этого, в случае вашего вызова test
, первый элемент входного массива - это другой массив , который сам по себе не далее перечисляется. Get-Member -InputObject (1,2) -Type Property
показывает, что массив имеет 8 свойств (Count
, IsFixedSize
, IsReadOnly
, IsSynchronized
, Length
, LongLength
, Rank
, SyncRoot
), поэтому Format-List
выбирается, перечисляя каждое свойство как пару имя / значение в отдельной строке.
Конечно, вы можете явно использовать командлет форматирования , и PetSerAl указывает, что командлеты форматирования поддерживают параметр -Expand
, который дает вам возможность контролировать форматирование объектов ввода, являющихся коллекциями. : вы можете попросить перечислить коллекцию, т. е. вывести ее элементы (-Expand EnumOnly
, которая является значением по умолчанию), чтобы показать только собственные свойства коллекции без печати ее элементов (-Expand CoreOnly
) или оба (-Expand Both
).
Обратите внимание, однако, что вы не можете запросить дополнительные уровни перечисления через -Expand
, поэтому ваш вывод test
не может быть напрямую отформатирован для отображения отдельных элементов вашего вложенного массива.
Однако это легко сделать, отправив по трубопроводу Write-Output
, который выполняет дополнительный уровень перечисления, необходимый для визуализации элементов по отдельности:
test | Write-Output
[1] Точнее, как указывает PetSerAl, это: . { test } 2>&1 | Out-Default
, что позволяет пользователям переопределять командлет Out-Default
для пользовательского форматирования.