在 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"))

更新:


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'