#powershell
#powershell
Вопрос:
У меня есть следующий оператор powershell, который я пытаюсь понять, в частности, какой тип он делает своей переменной.
[double] [boolean] $x = 12.5
$x
$x.GetType()
$x = .5
Результаты 3-х использований $ x:
1
Double
1
Итак, означает ли это, что $x всегда преобразует свои значения в логическое значение, но затем возвращает его как Double ?
Есть ли страница, которая документирует, что это должно делать?
Ответ №1:
Итак, означает ли это, что
$x
всегда преобразует свои значения в логическое значение, но затем возвращает его как Double
Вроде того, да. 12.5
(и любое последующее значение, присвоенное переменной) преобразуется в логическое значение $true
, а затем $true
преобразуется в числовое значение 1.0
.
Чтобы понять почему, я думаю, было бы полезно рассмотреть, как работает типизация переменных в PowerShell.
Из раздела about_Variables
справки:
Типы переменных
В переменной можно хранить объекты любого типа, включая целые числа, строки, массивы и хэш-таблицы. И объекты, представляющие процессы, службы, журналы событий и компьютеры.
Переменные PowerShell свободно типизированы, что означает, что они не ограничены определенным типом объекта. Одна переменная может даже содержать коллекцию или массив объектов разных типов одновременно.
Тип данных переменной определяется .ЧИСТЫЕ типы значений переменной.
(курсив добавлен)
То есть:
- Переменные в PowerShell НЕ вводятся интризически
- Результирующий тип выражения переменной полностью зависит от сохраненного значения
Итак, что PowerShell предоставляет нам для управления типом значения, присвоенного переменной? Из того же раздела раздела справки выше:
Вы можете использовать атрибут типа и обозначение приведения, чтобы гарантировать, что переменная может содержать только определенные типы объектов или объекты, которые могут быть преобразованы в этот тип. Если вы пытаетесь присвоить значение другого типа, PowerShell пытается преобразовать значение в его тип. Если тип не может быть преобразован, оператор присваивания завершается ошибкой.
Чтобы использовать приведенную нотацию, введите имя типа, заключенное в квадратные скобки, перед именем переменной (в левой части инструкции присваивания). В следующем примере создается
$number
переменная, которая может содержать только целые числа, […][int]$number = 8 $number = "12345" # The string is converted to an integer. $number = "Hello" # ArgumentTransformationMetadataException thrown
Итак, PowerShell фактически не вводит саму переменную, но добавляет к ней что-то, что заставляет ее пытаться преобразовать тип при назначении — давайте посмотрим на это «что-то», что он добавляет.
Начните с присвоения переменной значения нужного типа, не пытаясь выполнить приведение с левой стороны:
PS ~> $aBool = $true
PS ~> $aBool -is [bool]
True
PS ~> Get-Variable -Name aBool |Format-List
Name : aBool
Description :
Value : True
Visibility : Public
Module :
ModuleName :
Options : None
Attributes : {}
Обратите внимание, что (строковое представление) значения, True
, выглядит правильно, но нет реального указания его типа — точно так, как мы ожидаем от действительно «свободно типизированной» переменной.
Теперь давайте сделаем то же самое, но с использованием приведенной выше нотации:
PS ~> [bool]$aBool = 123 # Let's assign a non-[bool] value to a variable with a left-hand cast
PS ~> $aBool -is [bool] # resulting value is still [bool], as expected
True
PS ~> Get-Variable -Name aBool |Format-List
Name : aBool
Description :
Value : True
Visibility : Public
Module :
ModuleName :
Options : None
Attributes : {System.Management.Automation.ArgumentTypeConverterAttribute}
PS ~> (Get-Variable -Name aBool).Attributes |Get-Member
TypeName: System.Management.Automation.ArgumentTypeConverterAttribute
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
IsDefaultAttribute Method bool IsDefaultAttribute()
Match Method bool Match(System.Object obj)
ToString Method string ToString()
Transform Method System.Object Transform(System.Management.Automation.EngineIntrinsics engineIntrinsics, System.Object inputData)
TransformNullOptionalParameters Property bool TransformNullOptionalParameters {get;}
TypeId Property System.Object TypeId {get;}
Ага! У переменной по-прежнему нет типа, но теперь она содержит ArgumentTypeConverter
атрибут.
Сам атрибут type converter также не является строго типизированным, но он всегда будет либо возвращать значение типа, указанного в приведении слева (или выдает ошибку преобразования):
PS ~> $typeConverter = (Get-Variable aBool).Attributes[0]
PS ~> $typeConverter.Transform($ExecutionContext, 123)
True
PS ~> $typeConverter.Transform($ExecutionContext, '')
False
Поэтому, когда вы пишете оператор присваивания с несколькими приведениями типов в левой части выражения, PowerShell просто сохраняет весь список как отдельные атрибуты преобразователя типов:
PS ~> [double][bool]$aDoubleBool = 123
PS ~> (Get-Variable aDoubleBool).Attributes
TransformNullOptionalParameters TypeId
------------------------------- ------
True System.Management.Automation.ArgumentTypeConverterAttribute
True System.Management.Automation.ArgumentTypeConverterAttribute
Мы не можем точно сказать по выводам, но первый — это преобразователь типов, сгенерированный из [bool]
, последний — для [double]
, то есть PowerShell связывает их, от самого правого до самого левого.
Мы можем повторить это поведение, вручную связав преобразования:
PS ~>
>> (Get-Variable aDoubleBool).Attributes |%{
>> $value = $_.Transform($ExecutionContext, $value)
>> }
PS ~> $value -is [double]
True
PS ~> $value
1
Таким образом, вы можете добавлять и вычитать столько десятичных значений, сколько захотите, присвоенное значение всегда будет 0.0
или 1.0
из-за [bool]
-> [double]
преобразования 🙂