在 Powershell 6.0 中设置变量默认值的优雅方式?
Elegant way of setting default value for variable in Powershell 6.0?
我有以下的,它可以工作但看起来很笨重:
if($config.contentDir){
$contentDir = $config.contentDir
} else {
$contentDir = "contents"
}
有更好的方法吗?我看过这个答案 here,但不完全是 "nicer"。只是想知道 6.0 是否带来了任何改进?
我可能要处理大量的配置选项,所以它会变得相当混乱。
这个有点短...
$contentDir = if ( $config.contentDir ) { $config.contentDir } else { "contents" }
您还可以定义一个 iif
函数:
function iif {
param(
[ScriptBlock] $testExpr,
[ScriptBlock] $trueExpr,
[ScriptBlock] $falseExpr
)
if ( & $testExpr ) {
& $trueExpr
}
else {
& $falseExpr
}
}
那么你可以缩短为:
$contentDir = iif { $config.contentDir } { $config.contentDir } { "contents" }
顺便说一句,看起来下一个版本的 PowerShell 将支持 ternary operator (see https://devblogs.microsoft.com/powershell/powershell-7-preview-4/),所以在未来,您将能够编写如下内容:
$contentDir = $config.contentDir ? $config.contentDir : "contents"
如 Bill_Stewart
所示,ps7 中有一个三元运算符。但是,您可以通过使用两项数组并利用 PoSh 强制值的方式来获得类似的结果——$False
给出 0
,$True
给出 1
。
$Config = [PSCustomObject]@{
ContentDir = 'SomewhereElse'
}
#$Config.ContentDir = ''
$ContentDir = @('contents', $Config.ContentDir)[[bool]$Config.ContentDir]
$ContentDir
注释掉第 4 行的输出 = SomewhereElse
启用第 4 行的输出 = contents
有点像“||”在 bash。如果第一个为 false 或 null,它将执行第二个。
[void](($contentDir = $config.contentDir) -or ($contentDir = "contents"))
更新:
Null-coalescing operators were introduced in PowerShell (Core) 7.0 (along with a ternary operator), 启用以下 v7+ 解决方案:
$contentDir = $config.contentDir ?? 'content'
PowerShell v6- 解决方案:
您要查找的是 null-coalescing,PowerShell 在 v7.0.0-preview.4 中没有。
现在,必须这样做:
$contentDir = if ($null -eq $config.contentDir) { 'content' } else { $config.contentDir }
注意:$null
被特意放在 -eq
的左轴上,以明确测试 $null
,因为作为右轴,它会充当 filter 如果要测试的值恰好是 array-valued.
的改编使 更简洁 解决方案:
$contentDir = ($config.ContentDir, 'content')[$null -eq $config.ContentDir]
使用 ternary operator (conditional),将在 v7.0 中实现,实现 同样简洁 等效:
$contentDir = $null -eq $config.contentDir ? 'content' : $config.contentDir
但是,所有这些方法都具有以下不理想的方面:
它们需要明确引用 $null
;请注意 if ($config.ContentDir)
- 即将值强制转换为布尔值 - 可以与 字符串 一起使用,但通常并不稳健,因为非 $null
值如 0
也可以计算为 $false
。
$config.contentDir
,要测试 $null
的值,必须访问 两次 ,这可能会产生副作用。
定义一个 自定义函数 命名,比如说 ??
,可以解决这些问题:
# Custom function that emulates null-coalescing.
function ?? ($PossiblyNull, $ValueIfNull) {
if ($null -eq $PossiblyNull) { $ValueIfNull } else { $PossiblyNull }
}
$contentDir = ?? $config.contentDir 'content'
但是,这样的自定义函数有 缺点:
自定义函数的缺点是:
您需要包含或导入它们到您想要使用它们的每一段代码中。
如果您选择熟悉的名称,例如 ??
,操作数的位置可能会令人困惑,因为您必须(总是)以不同的方式放置它们在 PowerShell 中,假设实现为 function(例如,C# 中的 a ?? b
与 PowerShell 中的 ?? $a $b
)——尤其是在 PowerShell 中实现真正的空合并后: 请参阅下一节。
当然,调用函数会增加开销。
如果实现了this GitHub feature request,您将能够使用真正的空合并,这是最简洁的[=108] =] 解决方案并且 避免了上述不良方面:
# Hopefully soon
$contentDir = $config.contentDir ?? 'content'
链接的 GitHub 问题中还提出了一个相关的特征是 空条件赋值 、$config.ContentDir ?= 'content'
我有以下的,它可以工作但看起来很笨重:
if($config.contentDir){
$contentDir = $config.contentDir
} else {
$contentDir = "contents"
}
有更好的方法吗?我看过这个答案 here,但不完全是 "nicer"。只是想知道 6.0 是否带来了任何改进?
我可能要处理大量的配置选项,所以它会变得相当混乱。
这个有点短...
$contentDir = if ( $config.contentDir ) { $config.contentDir } else { "contents" }
您还可以定义一个 iif
函数:
function iif {
param(
[ScriptBlock] $testExpr,
[ScriptBlock] $trueExpr,
[ScriptBlock] $falseExpr
)
if ( & $testExpr ) {
& $trueExpr
}
else {
& $falseExpr
}
}
那么你可以缩短为:
$contentDir = iif { $config.contentDir } { $config.contentDir } { "contents" }
顺便说一句,看起来下一个版本的 PowerShell 将支持 ternary operator (see https://devblogs.microsoft.com/powershell/powershell-7-preview-4/),所以在未来,您将能够编写如下内容:
$contentDir = $config.contentDir ? $config.contentDir : "contents"
如 Bill_Stewart
所示,ps7 中有一个三元运算符。但是,您可以通过使用两项数组并利用 PoSh 强制值的方式来获得类似的结果——$False
给出 0
,$True
给出 1
。
$Config = [PSCustomObject]@{
ContentDir = 'SomewhereElse'
}
#$Config.ContentDir = ''
$ContentDir = @('contents', $Config.ContentDir)[[bool]$Config.ContentDir]
$ContentDir
注释掉第 4 行的输出 = SomewhereElse
启用第 4 行的输出 = contents
有点像“||”在 bash。如果第一个为 false 或 null,它将执行第二个。
[void](($contentDir = $config.contentDir) -or ($contentDir = "contents"))
更新:
Null-coalescing operators were introduced in PowerShell (Core) 7.0 (along with a ternary operator), 启用以下 v7+ 解决方案:
$contentDir = $config.contentDir ?? 'content'
PowerShell v6- 解决方案:
您要查找的是 null-coalescing,PowerShell 在 v7.0.0-preview.4 中没有。
现在,必须这样做:
$contentDir = if ($null -eq $config.contentDir) { 'content' } else { $config.contentDir }
注意:$null
被特意放在 -eq
的左轴上,以明确测试 $null
,因为作为右轴,它会充当 filter 如果要测试的值恰好是 array-valued.
$contentDir = ($config.ContentDir, 'content')[$null -eq $config.ContentDir]
使用 ternary operator (conditional),将在 v7.0 中实现,实现 同样简洁 等效:
$contentDir = $null -eq $config.contentDir ? 'content' : $config.contentDir
但是,所有这些方法都具有以下不理想的方面:
它们需要明确引用
$null
;请注意if ($config.ContentDir)
- 即将值强制转换为布尔值 - 可以与 字符串 一起使用,但通常并不稳健,因为非$null
值如0
也可以计算为$false
。$config.contentDir
,要测试$null
的值,必须访问 两次 ,这可能会产生副作用。
定义一个 自定义函数 命名,比如说 ??
,可以解决这些问题:
# Custom function that emulates null-coalescing.
function ?? ($PossiblyNull, $ValueIfNull) {
if ($null -eq $PossiblyNull) { $ValueIfNull } else { $PossiblyNull }
}
$contentDir = ?? $config.contentDir 'content'
但是,这样的自定义函数有 缺点:
自定义函数的缺点是:
您需要包含或导入它们到您想要使用它们的每一段代码中。
如果您选择熟悉的名称,例如
??
,操作数的位置可能会令人困惑,因为您必须(总是)以不同的方式放置它们在 PowerShell 中,假设实现为 function(例如,C# 中的a ?? b
与 PowerShell 中的?? $a $b
)——尤其是在 PowerShell 中实现真正的空合并后: 请参阅下一节。当然,调用函数会增加开销。
如果实现了this GitHub feature request,您将能够使用真正的空合并,这是最简洁的[=108] =] 解决方案并且 避免了上述不良方面:
# Hopefully soon
$contentDir = $config.contentDir ?? 'content'
链接的 GitHub 问题中还提出了一个相关的特征是 空条件赋值 、$config.ContentDir ?= 'content'