Joa*_*hal 1 powershell types casting type-conversion
这是一个例子,真实的东西是一个大的New-Object 'object[,]'二维数组:
PS C:\> $a=[int16]10
PS C:\> $a.GetType().Name
Int16
PS C:\> $a++
PS C:\> $a.GetType().Name
Int32
PS C:\> $a=[int16]10
PS C:\> $a.GetType().Name
Int16
PS C:\> $a=$a+[int16]1
PS C:\> $a.GetType().Name
Int32
Run Code Online (Sandbox Code Playgroud)
我可以在此类事情中强制使用类型,但这实际上是数学完成后的转换,并且会使完整代码减慢约 10%,因此它是无用的:
PS C:\> $a=[int16]10
PS C:\> $a.GetType().Name
Int16
PS C:\> $a=[int16]($a+1)
PS C:\> $a.GetType().Name
Int16
Run Code Online (Sandbox Code Playgroud)
在使用任何数学时,是否没有办法阻止从 byte 和 int16 到它喜爱的 int32 的自动转换?
至于@mklement0 的评论,我将示例扩展到用例。请注意,该板上任何位置的值都不会超过“8”:
# Init board
$BoardXSize = [int]100
$BoardYSize = [int]100
$Board = New-Object 'object[,]' $BoardXSize,$BoardYSize
for ($y=0;$y -lt $BoardYSize;$y++) {
for ($x=0;$x -lt $BoardXSize;$x++) {
[int16]$Board[$x,$y] = 0
}
}
Run Code Online (Sandbox Code Playgroud)
测试:
PS C:\> ($Board[49,49]).GetType().Name
Int16
PS C:\> $Board[49,49]++
PS C:\> ($Board[49,49]).GetType().Name
Int32
PS C:\> [int16]$Board[49,49]=0
PS C:\> ($Board[49,49]).GetType().Name
Int16
PS C:\> [int16]$Board[49,49]++
0
PS C:\> ($Board[49,49]).GetType().Name
Int32
PS C:\> [int16]$Board[49,49]=0
PS C:\> ($Board[49,49]).GetType().Name
Int16
PS C:\> $Board[49,49] += [int16]1
PS C:\> ($Board[49,49]).GetType().Name
Int32
PS C:\> [byte]$Board[49,49]=0
PS C:\> ($Board[49,49]).GetType().Name
Byte
PS C:\> $Board[49,49] += [byte]1
PS C:\> ($Board[49,49]).GetType().Name
Int32
Run Code Online (Sandbox Code Playgroud)
然而,当对其工作的运算符极其挑剔时,仅“++”似乎会失败:
PS C:\> [int16]$Board[49,49]=0
PS C:\> ($Board[49,49]).GetType().Name
Int16
PS C:\> [int16]$Board[49,49] += [int16]1
PS C:\> ($Board[49,49]).GetType().Name
Int16
PS C:\> [byte]$Board[49,49]=0
PS C:\> ($Board[49,49]).GetType().Name
Byte
PS C:\> [byte]$Board[49,49] += [byte]1
PS C:\> ($Board[49,49]).GetType().Name
Byte
Run Code Online (Sandbox Code Playgroud)
但由于这总是在数学完成后进行转换,因此不会提高速度。但已经解决了。
\n
您可以通过将类型文字放置在(初始)赋值的左侧来对变量进行类型约束:
\n# Note how [int16] is to the *left* of $a = ...\nPS> [int16] $a = 10; ++$a; $a += 1; $a, $a.GetType().Name\n12\nInt16\nRun Code Online (Sandbox Code Playgroud)\n请注意,这与在静态类型语言(例如 C#)中键入变量的工作方式不同,例如:不是静态锁定指定类型,而是对每个赋值执行强制转换,以强制分配给该类型的值。
\n例如, with[int16] $a = 10是原始分配,$a += 1实际上与分配 相同[int16] ($a + 1)。
这也意味着您可以自由地分配任何类型的值,只要它们可以转换为约束类型即可;例如:
\n# These work, because they are implicitly cast (converted) to [int16]\n$a += 1.2\n$a += \'42\'\nRun Code Online (Sandbox Code Playgroud)\n请参阅下一节有关数组的内容。
\n对数组应用类型约束:
\n对于(一维)数组:
\n# Strongly types the array as storing [int16] instances\n# *and* type-constrains the $arr variable.\nPS> [int16[]] $arr = 10, 11; ++$arr[0]; $arr[1] += 1; $arr; $arr.ForEach(\'GetType\').Name\n11\n12\nInt16\nInt16\nRun Code Online (Sandbox Code Playgroud)\n二维数组(在 PowerShell 中很少见):
\n# Strongly types the 2D array as storing [int16] instances,\n# but does *not* type-constrain the $arr2d *variable.\nPS> $countDim1, $countDim2 = 2, 3;\n $arr2d = [int16[,]]::new($countDim1, $countDim2);\n ++$arr2d[0,0]; $arr2d[0,0].GetType().Name\nInt16\nRun Code Online (Sandbox Code Playgroud)\n请注意,这确实创建了强静态类型的 .NET 数组,但分配给它们的元素再次应用了 PowerShell 的灵活类型转换(例如,$arr[0] = \'42\'工作正常)。
另请注意,为简洁起见,二维数组示例实际上并未对变量的数据类型进行类型约束,因为赋值左侧没有类型文字;因此,您仍然可以用任何类型的任意新值替换整个数组(例如,$arr2d = \'foo\');要也执行类型约束,您必须执行以下操作:
# Creates a 2D [int16] array *and* type-constrains $arr2D to\n# such arrays.\n[int16[,]] $arr2d = [int16[,]]::new($countDim1, $countDim2)\nRun Code Online (Sandbox Code Playgroud)\n最后,请注意,您不能对数组的各个元素或对象的(可写)属性进行类型约束;换句话说:只有作为PowerShell 变量的L 值才能受到类型约束;[1]在所有其他情况下,执行简单的临时转换;例如,给定一个[object[]]array $a = 1, 2,以下两个语句是等效的:
# Cast\n$a[0] = [int] 42 \n\n# !! A mere cast too, because the assignment target is an \n# !! *array element*, which cannot be type-constrained.\n[int] $a[0] = 42\nRun Code Online (Sandbox Code Playgroud)\n与 C# 等语言不同的是,PowerShell 会自动扩展数值运算中的类型。
\n这种扩大不仅适用于不同(数字)类型的操作数,而且还适用于结果太大而无法适应(两个中较大的)输入类型的情况,并且它有两个令人惊讶的方面:
\n应用最小宽度 ( ),这意味着小于的类型始终会加宽到[int]System.Int32[int][int],即使没有必要,正如您所观察到的
# Implicitly widens to [int], even though not necessary.\n# Note that the [byte] cast is only applied to the LHS\nPS> ([byte] 42 + 1).GetType().Name\nInt32\nRun Code Online (Sandbox Code Playgroud)\n如果结果太大而无法适应(两个中较大的)输入类型,则结果总是会扩展为[double]( System.Double)(!)
# Implicitly widens to [double](!), because adding 1\n# to the max. [int] value doesn\'t fit into an [int].\nPS> ([int]::MaxValue + 1).GetType().Name\nDouble\n\n# NO widening, because the large input type is a [long] (System.Int64)\n# (suffix L), so the result fits into a [long] too.\nPS> ([long] [int]::MaxValue + 1).GetType().Name\nInt64\nRun Code Online (Sandbox Code Playgroud)\n这种立即扩展到[double]in 表达式(不考虑更大的整数类型)的方式与 PowerShell 中解析数字文字的方式不同,在 PowerShell 中使用更大的整数类型(但请注意,PowerShell 从不选择无符号类型):
# 2147483648 = [int]::MaxValue + 1, so [long] (System.Int64)\n# is chose as the literal\'s type. \n(2147483648).GetType().Name\nIn64\nRun Code Online (Sandbox Code Playgroud)\nlfor[long]和dfor [decimal]; 例如,2147483648d.GetType().Name返回Decimal.[object[]]:例如,PowerShell 的常规数组类型(由,和运算符创建)是,即“无类型”数组,作为 .NET 类型层次结构的根,可以存储任何数据类型的值 - 甚至允许在给定的单个数组中混合不同类型。@(...)[object[]][object]
虽然这提供了很大的灵活性,但它会影响:
\n类型安全:根据用例,可能需要确保所有元素具有相同的类型;如果是这样,请使用强类型数组。
\n内存效率:值类型实例必须包装在[object]实例中进行存储,这个过程称为装箱,并且在访问时需要拆开包装,称为拆箱。
运行时性能:令人惊讶的是,与装箱和拆箱的开销不同,几乎没有任何影响性能优势,而且对于 2D 数组,性能甚至会受到影响。
\n以下是数组获取和设置访问基准测试的结果,将具有各种值类型的一维和二维数组与普通数组进行比较。object元素的一维和二维数组进行比较:
使用 100 万个元素的一维数组和 1000 x 1000 的二维数组对 15 次运行进行平均。
\n基准测试源代码如下。
\n要自己运行代码,您需要首先Time-Command从这个要点下载并定义函数。
假设您已经查看了链接的 Gist 的源代码以确保它是安全的(我个人可以向您保证,但您应该始终检查),您可以直接安装它,如下所示:
\nirm https://gist.github.com/mklement0/9e1f13978620b09ab2d15da5535d1b27/raw/Time-Command.ps1 | iex\nRun Code Online (Sandbox Code Playgroud)\nPowerShell 中的基准测试远非一门精确的科学。由于基准测试是基于挂钟的,因此最好对多次运行进行平均,并确保系统不会(太)忙于运行其他事情。
\n绝对时间会根据许多因素而变化,但该Factor列应该提供相对性能的感觉 - 小数点后第二位的差异可能是偶然的(例如,1.00与1.03),并且此类排名可能会在重复调用中交换位置。
以下结果得出一些结论,这些结果是在 Windows 10 计算机上的PowerShell (Core) 7.2.2上运行的- Windows PowerShell性能特征可能有所不同:
\n一维数组(迄今为止 PowerShell 中最常见的数组类型):
\n二维数组(在 PowerShell 中很少见):
\n注意:虽然下面没有 Windows PowerShell 结果,但在我的测试中,PowerShell (Core) 7+ 中数组访问的速度似乎增加了一倍。
\n# Sample results on a Windows 10 machine running PowerShell 7.2.2\n\n============== 1D: GET performance (avg. of 15 runs)\n\nFactor Secs (15-run avg.) Command\n------ ------------------ -------\n1.00 0.482 # [byte[]]\xe2\x80\xa6\n1.00 0.483 # [int[]] (Int32)\xe2\x80\xa6\n1.01 0.487 # [long[]]\xe2\x80\xa6\n1.02 0.492 # [int16[]]\xe2\x80\xa6\n1.08 0.521 # [decimal[]]\xe2\x80\xa6\n1.09 0.526 # [object[]]\xe2\x80\xa6\n1.11 0.533 # [double[]]\xe2\x80\xa6\n1.12 0.537 # [datetime[]]\xe2\x80\xa6\n\n============== 1D: SET (INCREMENT) performance (avg. of 15 runs)\n\nFactor Secs (15-run avg.) Command\n------ ------------------ -------\n1.00 0.526 # [double[]]\xe2\x80\xa6\n1.03 0.541 # [int[]] (Int32)\xe2\x80\xa6\n1.11 0.584 # [long[]]\xe2\x80\xa6\n1.30 0.681 # [byte[]]\xe2\x80\xa6\n1.40 0.738 # [int16[]]\xe2\x80\xa6\n1.57 0.826 # [decimal[]]\xe2\x80\xa6\n1.86 0.975 # [object[]], no casts\xe2\x80\xa6\n2.90 1.523 # [object[]] with [int] casts\xe2\x80\xa6\n7.34 3.857 # [datetime[]]\xe2\x80\xa6\n\n============== 2D: GET performance (avg. of 15 runs)\n\nFactor Secs (15-run avg.) Command\n------ ------------------ -------\n1.00 0.620 # [object[,]]\xe2\x80\xa6\n1.13 0.701 # [double[,]]\xe2\x80\xa6\n1.13 0.702 # [int[,]] (Int32)\xe2\x80\xa6\n1.18 0.731 # [datetime[,]]\xe2\x80\xa6\n1.20 0.747 # [long[,]]\xe2\x80\xa6\n1.23 0.764 # [byte[,]]\xe2\x80\xa6\n1.26 0.782 # [decimal[,]]\xe2\x80\xa6\n1.34 0.828 # [int16[,]]\xe2\x80\xa6\n\n============== 2D: SET (INCREMENT) performance (avg. of 15 runs)\n\nFactor Secs (15-run avg.) Command\n------ ------------------ -------\n1.00 0.891 # [double[,]]\xe2\x80\xa6\n1.02 0.904 # [long[,]]\xe2\x80\xa6\n1.10 0.977 # [byte[,]]\xe2\x80\xa6\n1.24 1.107 # [object[,]], no casts\xe2\x80\xa6\n1.27 1.131 # [int16[,]]\xe2\x80\xa6\n1.28 1.143 # [int[,]] (Int32)\xe2\x80\xa6\n1.46 1.300 # [decimal[,]]\xe2\x80\xa6\n1.72 1.530 # [object[,]] with [int] casts\xe2\x80\xa6\n5.25 4.679 # [datetime[,]]\xe2\x80\xa6\nRun Code Online (Sandbox Code Playgroud)\n基准源代码:
\n$runs = 15 # how many run to average.\n$d1 = $d2 = 1000 # 1000 x 1000 2D array\n$d = $d1 * $d2 # 1 million-element 1D array\n\n# index arrays for looping\n$indices_d1 = 0..($d1 - 1)\n$indices_d2 = 0..($d2 - 1)\n$indices = 0..($d - 1)\n\n# 1D arrays.\n$ao = [object[]]::new($d)\n$ab = [byte[]]::new($d)\n$ai16 = [int16[]]::new($d)\n$ai = [int[]]::new($d)\n$al = [long[]]::new($d)\n$adec = [decimal[]]::new($d)\n$ad = [double[]]::new($d)\n$adt = [datetime[]]::new($d)\n\n# 2D arrays.\n$ao_2d = [object[,]]::new($d1, $d2)\n$ab_2d = [byte[,]]::new($d1, $d2)\n$ai16_2d = [int16[,]]::new($d1, $d2)\n$ai_2d = [int[,]]::new($d1, $d2)\n$al_2d = [long[,]]::new($d1, $d2)\n$adec_2d = [decimal[,]]::new($d1, $d2)\n$ad_2d = [double[,]]::new($d1, $d2)\n$adt_2d = [datetime[,]]::new($d1, $d2)\n\n"`n============== 1D: GET performance (avg. of $runs runs)"\n\nTime-Command -Count $runs `\n{ # [object[]]\n foreach ($i in $indices) { $null = $ao[$i] }\n},\n{ # [byte[]]\n foreach ($i in $indices) { $null = $ab[$i] }\n}, \n{ # [int16[]]\n foreach ($i in $indices) { $null = $ai16[$i] }\n},\n{ # [int[]] (Int32)\n foreach ($i in $indices) { $null = $ai[$i] }\n},\n{ # [long[]]\n foreach ($i in $indices) { $null = $al[$i] }\n}, \n{ # [decimal[]]\n foreach ($i in $indices) { $null = $adec[$i] }\n}, \n{ # [double[]]\n foreach ($i in $indices) { $null = $ad[$i] }\n},\n{ # [datetime[]]\n foreach ($i in $indices) { $null = $adt[$i] }\n} | Format-Table Factor, Secs*, Command\n\n"============== 1D: SET (INCREMENT) performance (avg. of $runs runs)"\n\nTime-Command -Count $runs `\n{ # [object[]], no casts\n foreach ($i in $indices) { ++$ao[$i] }\n},\n{ # [object[]] with [int] casts\n foreach ($i in $indices) { $ao[$i] = [int] ($ao[$i] + 1) }\n},\n{ # [byte[]]\n foreach ($i in $indices) { ++$ab[$i] }\n}, \n{ # [int16[]]\n foreach ($i in $indices) { ++$ai16[$i] }\n},\n{ # [int[]] (Int32)\n foreach ($i in $indices) { ++$ai[$i] }\n},\n{ # [long[]]\n foreach ($i in $indices) { ++$al[$i] }\n},\n{ # [decimal[]]\n foreach ($i in $indices) { ++$adec[$i] }\n},\n{ # [double[]]\n foreach ($i in $indices) { ++$ad[$i] }\n},\n{ # [datetime[]]\n foreach ($i in $indices) { $adt[$i] += 1 } # ++ not supported\n} | Format-Table Factor, Secs*, Command\n\n"============== 2D: GET performance (avg. of $runs runs)"\n\nTime-Command -Count $runs `\n{ # [object[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $null = $ao_2d[$i, $j] }\n }\n},\n{ # [byte[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $null = $ab_2d[$i, $j] } \n }\n},\n{ # [int16[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $null = $ai16_2d[$i, $j] }\n }\n}, \n{ # [int[,]] (Int32)\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $null = $ai_2d[$i, $j] }\n }\n},\n{ # [long[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $null = $al_2d[$i, $j] } \n }\n}, \n{ # [decimal[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $null = $adec_2d[$i, $j] } \n }\n},\n{ # [double[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $null = $ad_2d[$i, $j] } \n }\n}, \n{ # [datetime[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $null = $adt_2d[$i, $j] } \n }\n} | Format-Table Factor, Secs*, Command\n\n"============== 2D: SET (INCREMENT) performance (avg. of $runs runs)"\n\nTime-Command -Count $runs `\n{ # [object[,]], no casts\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { ++$ao_2d[$i, $j] }\n }\n},\n{ # [object[,]] with [int] casts\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $ao_2d[$i, $j] = [int] ($ao_2d[$i, $j] + 1) }\n }\n}, \n{ # [byte[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { ++$ab_2d[$i, $j] }\n }\n}, \n{ # [int16[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { ++$ai16_2d[$i, $j] }\n }\n},\n{ # [int[,]] (Int32)\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { ++$ai_2d[$i, $j] }\n }\n},\n{ # [long[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { ++$al_2d[$i, $j] }\n }\n}, \n{ # [decimal[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { ++$adec_2d[$i, $j] } \n }\n},\n{ # [double[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { ++$ad_2d[$i, $j] } \n }\n},\n{ # [datetime[,]]\n foreach ($i in $indices_d1) {\n foreach ($j in $indices_d2) { $adt_2d[$i, $j] += 1 } # ++ not supported\n }\n} | Format-Table Factor, Secs*, Command\nRun Code Online (Sandbox Code Playgroud)\n[1] 原因是类型约束需要将类型转换属性附加到 PowerShell 变量对象。
\n| 归档时间: |
|
| 查看次数: |
393 次 |
| 最近记录: |