Powershell 中是否存在空合并运算符?
我希望能够在 powershell 中执行这些 c # 命令:
var s = myval ?? "new value"; var x = myval == null ? "" : otherval;
如果你安装了 Powershell 社区扩展模块,你可以使用:
是 Invoke-NullCoalesching 的别名。
$s = ?? {$myval} {"New Value"}
是 Invoke-Ternary 的别名。
$x = ?: {$myval -eq $null} {""} {$otherval}
Powershell 7在 Powershell 引入了 本机 null 合并、 null 条件赋值和三元运算符。
零聚结
$null ?? 100 # Result is 100 "Evaluated" ?? (Expensive-Operation "Not Evaluated") # Right side here is not evaluated
空的条件赋值
$x = $null $x ??= 100 # $x is now 100 $x ??= 200 # $x remains 100
三元操作员
$true ? "this value returned" : "this expression not evaluated" $false ? "this expression not evaluated" : "this value returned"
不需要 Powershell 社区扩展,可以使用标准的 Powershell if 语句作为表达式:
variable = if (condition) { expr1 } else { expr2 }
因此,为了替身计画你的第一个 c # 表达式:
var s = myval ?? "new value";
成为下列其中之一(取决于偏好) :
$s = if ($myval -eq $null) { "new value" } else { $myval } $s = if ($myval -ne $null) { $myval } else { "new value" }
或者根据 $myval 可能包含的内容,您可以使用:
$s = if ($myval) { $myval } else { "new value" }
第二个 C # 表达式以类似的方式映射:
var x = myval == null ? "" : otherval;
变成了
$x = if ($myval -eq $null) { "" } else { $otherval }
现在,公平地说,这些并不是很快捷,而且远不如 C # 表单使用起来那么舒适。
您也可以考虑将其包装在一个非常简单的函数中,以使其更具可读性:
function Coalesce($a, $b) { if ($a -ne $null) { $a } else { $b } } $s = Coalesce $myval "new value"
或者可能是 IfNull:
function IfNull($a, $b, $c) { if ($a -eq $null) { $b } else { $c } } $s = IfNull $myval "new value" $myval $x = IfNull $myval "" $otherval
正如你所看到的,一个非常简单的函数可以给你相当多的语法自由。
更新: 在混合中需要考虑的另一个选项是更通用的 IsTrue 函数:
function IfTrue($a, $b, $c) { if ($a) { $b } else { $c } } $x = IfTrue ($myval -eq $null) "" $otherval
然后结合 Powershell 声明看起来有点像操作符的别名的能力,最终得到:
New-Alias "??" Coalesce $s = ?? $myval "new value" New-Alias "?:" IfTrue $ans = ?: ($q -eq "meaning of life") 42 $otherval
显然这不是每个人都喜欢的,但可能是你想要的。
正如托马斯指出的那样,c # 版本和上述版本的另一个细微差别是,c # 执行短路参数,但是涉及函数/别名的 Powershell 版本总是计算所有参数。如果这是一个问题,使用 if表达式表单。
if
function coalesce { Param ([string[]]$list) #$default = $list[-1] $coalesced = ($list -ne $null) $coalesced[0] } function coalesce_empty { #COALESCE for empty_strings Param ([string[]]$list) #$default = $list[-1] $coalesced = (($list -ne $null) -ne '')[0] $coalesced[0] }
PowerShell 7引入了许多新特性,并从。NET 架构,以。NET 核心。到2020年中期,它还没有完全取代 PowerShell 的遗留版本,因为它依赖于。NET 核心,但微软表示,他们打算为核心家庭最终取代遗留的框架家庭。在您阅读本文时,您的系统上可能已经预先安装了兼容的 PowerShell 版本; 如果没有,请参阅 https://github.com/powershell/powershell。
根据 文件,PowerShell 7.0支持以下运算符:
??
??=
... ? ... : ...
这些工作正如您所期望的空合并一样:
$x = $a ?? $b ?? $c ?? 'default value' $y ??= 'default value'
由于引入了一个三元运算符,下面的操作现在是可能的,尽管它是不必要的,因为添加了一个空合并运算符:
$x = $a -eq $null ? $b : $a
在7.0版本中,如果 PSNullConditionalOperators的可选特性是 启用,那么以下内容也是可用的,正如文档(1,2)中所解释的:
PSNullConditionalOperators
?.
?[]
这里有几点需要注意的地方:
${}
${x}?.Test()
$x?.Test()
$x?
Test()
?(
$x.Test?()
7之前的 PowerShell 版本确实有一个实际的空合并运算符,或者至少有一个能够执行这种行为的运算符。接线员是 -ne:
-ne
# Format: # ($a, $b, $c -ne $null)[0] ($null, 'alpha', 1 -ne $null)[0] # Output: alpha
它比空合并运算符更加通用,因为它创建了一个包含所有非空项的数组:
$items = $null, 'alpha', 5, 0, '', @(), $null, $true, $false $instances = $items -ne $null [string]::Join(', ', ($instances | ForEach-Object -Process { $_.GetType() })) # Result: System.String, System.Int32, System.Int32, System.String, System.Object[], System.Boolean, System.Boolean
-eq的工作原理类似,它对计算 null 条目非常有用:
-eq
($null, 'a', $null -eq $null).Length # Result: 2
但不管怎样,这里有一个镜像 C # 的 ??操作符的典型案例:
'Filename: {0}' -f ($filename, 'Unknown' -ne $null)[0] | Write-Output
这个解释是基于一个匿名用户的编辑建议。谢谢,不管你是谁!
根据操作顺序,工作顺序如下:
,
[0]
简而言之:
与 C # 的空合并运算符不同,每个可能的表达式都将被求值,因为第一步是创建一个数组。
这只是问题前半部分的一半答案,所以如果你愿意的话,四分之一的答案,但是有一个更简单的替代 null 合并运算符的方法,前提是你想使用的默认值实际上是类型的默认值:
string s = myval ?? "";
在 Powershell 可以这样写:
([string]myval)
或者
int d = myval ?? 0;
翻译过来就是 Powershell:
([int]myval)
我发现第一个在处理 xml 元素时很有用,这个 xml 元素可能不存在,而且如果存在的话,它周围可能有不想要的空格:
$name = ([string]$row.td[0]).Trim()
字符串强制转换可以防止元素为空,并防止 Trim()失败的任何风险。
Trim()
在使用聚合时,我经常发现还需要将空字符串视为 null。最后,我为此编写了一个函数,它使用 Zenexer的解决方案对简单的 null 合并进行合并,然后使用 Keith Hill的解决方案对 null 或空检查进行合并,并将其作为一个标志添加进来,这样我的函数就可以同时执行这两个操作。
这个函数的一个优点是,它还可以处理所有元素为 null (或空)的情况,而不会抛出异常。由于 PowerShell 处理数组输入的方式,它还可以用于任意多个输入变量。
function Coalesce([string[]] $StringsToLookThrough, [switch]$EmptyStringAsNull) { if ($EmptyStringAsNull.IsPresent) { return ($StringsToLookThrough | Where-Object { $_ } | Select-Object -first 1) } else { return (($StringsToLookThrough -ne $null) | Select-Object -first 1) } }
测试结果如下:
Null coallesce tests: 1 (w/o flag) - empty/null/'end' : 1 (with flag) - empty/null/'end' : end 2 (w/o flag) - empty/null : 2 (with flag) - empty/null : 3 (w/o flag) - empty/null/$false/'end' : 3 (with flag) - empty/null/$false/'end' : False 4 (w/o flag) - empty/null/"$false"/'end' : 4 (with flag) - empty/null/"$false"/'end' : False 5 (w/o flag) - empty/'false'/null/"$false"/'end': 5 (with flag) - empty/'false'/null/"$false"/'end': false
测试代码:
Write-Host "Null coalesce tests:" Write-Host "1 (w/o flag) - empty/null/'end' :" (Coalesce '', $null, 'end') Write-Host "1 (with flag) - empty/null/'end' :" (Coalesce '', $null, 'end' -EmptyStringAsNull) Write-Host "2 (w/o flag) - empty/null :" (Coalesce('', $null)) Write-Host "2 (with flag) - empty/null :" (Coalesce('', $null) -EmptyStringAsNull) Write-Host "3 (w/o flag) - empty/null/`$false/'end' :" (Coalesce '', $null, $false, 'end') Write-Host "3 (with flag) - empty/null/`$false/'end' :" (Coalesce '', $null, $false, 'end' -EmptyStringAsNull) Write-Host "4 (w/o flag) - empty/null/`"`$false`"/'end' :" (Coalesce '', $null, "$false", 'end') Write-Host "4 (with flag) - empty/null/`"`$false`"/'end' :" (Coalesce '', $null, "$false", 'end' -EmptyStringAsNull) Write-Host "5 (w/o flag) - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end') Write-Host "5 (with flag) - empty/'false'/null/`"`$false`"/'end':" (Coalesce '', 'false', $null, "$false", 'end' -EmptyStringAsNull)
$null, $null, 3 | Select -First 1
报税表
3
最接近的是 $Val = $MyVal |?? "Default Value"
$Val = $MyVal |?? "Default Value"
对于以上内容,我实现了 空合并运算符:
function NullCoalesc { param ( [Parameter(ValueFromPipeline=$true)]$Value, [Parameter(Position=0)]$Default ) if ($Value) { $Value } else { $Default } } Set-Alias -Name "??" -Value NullCoalesc
条件三元运算符条件三元运算符可以以类似的方式实现。
function ConditionalTernary { param ( [Parameter(ValueFromPipeline=$true)]$Value, [Parameter(Position=0)]$First, [Parameter(Position=1)]$Second ) if ($Value) { $First } else { $Second } } Set-Alias -Name "?:" -Value ConditionalTernary
用法类似于: $Val = $MyVal |?: $MyVal "Default Value"
$Val = $MyVal |?: $MyVal "Default Value"
最后,PowerShell 7得到了 空合并赋值运算符!
PS > $null ?? "a" a PS > "x" ?? "y" x PS > $x = $null PS > $x ??= "abc" PS > $x abc PS > $x ??= "xyz" PS > $x abc
@($null,$null,"val1","val2",5) | select -First 1
我也有过类似的问题。
当处理不存在的数组索引时,要简化这个过程要困难得多... ..。
或者更奇怪(但在 Powershell 也可能发生) 如果您试图从另一个尚未定义/创建的变量赋值..。
例子:
$x = $y # and $y id not defined/created yet -or- $x = $args[2] # and args has less than 3 elements
奇怪的是,我“估计”了一些选择,其中一个变得非常方便... ..。 我认为这与 Powershell 的函数式编程近似有关 事实上,“未经挖掘”的堆栈价值仍然留在管道中供下一个消费者使用..
so this works flawlessly:
$x = try{ $y } catch { 1 } # $x becomes 1 $x = try{ $a[ 2 ] } catch { 2 } #$ x becomes 2 $x = try{ $a[ 2 ] } catch { } #$ x becomes $null
它简化了很多代码。 甚至有助于高级处理可选参数 *
希望能有帮助!