【问题标题】:Elegant way of setting default value for variable in Powershell 6.0?在 Powershell 6.0 中为变量设置默认值的优雅方式?
【发布时间】:2019-09-23 21:01:40
【问题描述】:

我有以下内容,虽然可以,但看起来很笨重:

if($config.contentDir){ 
    $contentDir = $config.contentDir
} else { 
    $contentDir = "contents"
}

有更好的方法吗?我已经看到了这个答案here,但它并不完全“更好”。只是想知道 6.0 是否带来了任何改进?

我可能要处理大量的配置选项,所以会变得相当混乱。

【问题讨论】:

  • 我会注意到(并且因为那里没有支持而哭了一点):使用样板代码 `$contentDir = ~ $config.contentDir : "contents" 可以使用足够多更好。也就是说,在真正的三元运算符出现之前,一切都是黑客或@Bill_Stewart 所展示的更冗长代码的混合体。

标签: powershell powershell-6.0


【解决方案1】:

这有点短...

$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(请参阅https://devblogs.microsoft.com/powershell/powershell-7-preview-4/),因此在未来,您将能够编写如下代码:

$contentDir = $config.contentDir ? $config.contentDir : "contents"

【讨论】:

  • 谢谢 - 考虑到我正在做的工作和我的新手,我想在我完成之前我们会有 7.0。
【解决方案2】:

更新


PowerShell v6- 解决方案

您要查找的是 null-coalescing,PowerShell 在 v7.0.0-preview.4 中没有此功能。

目前,必须这样做:

$contentDir = if ($null -eq $config.contentDir) { 'content' } else { $config.contentDir }

注意:$null 被故意放置在 -eq 的 LHS 上以明确测试 $null,因为作为 RHS,如果值为test 恰好是 array-valued.

Lee Daily's array-based answer 的改编可实现更简洁的解决方案:

$contentDir = ($config.ContentDir, 'content')[$null -eq $config.ContentDir]

使用将在 v7.0 中实现的ternary operator (conditional) 可以实现同样简洁的等效项:

$contentDir = $null -eq $config.contentDir ? 'content' : $config.contentDir

但是,所有这些方法都有以下不受欢迎的方面

  • 它们需要明确引用$null;请注意,if ($config.ContentDir) - 即将值强制为布尔值 - 可以与 strings 一起使用,但通常不可靠,因为非$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 中以不同的方式放置它们,因为实现为 函数(例如,C# 中的 a ?? b 与 PowerShell 中的 ?? $a $b)——尤其是在 PowerShell 中实现真正的空合并后:请参阅下一节。

  • 当然,调用函数会增加开销。


如果实现this GitHub feature request,您将能够使用真正的空合并,这既是最简洁的解决方案,又避免了上述情况不良方面

# Hopefully soon
$contentDir = $config.contentDir ?? 'content'

在链接的 GitHub 问题中还提出了一个相关功能是 null-conditional assignment$config.ContentDir ?= 'content'

【讨论】:

    【解决方案3】:

    正如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

    【讨论】:

    • 数组解决方法很有趣,但 IMO 太神秘了。
    • @Bill_Stewart - 是的,这有点离谱...... [grin]
    【解决方案4】:

    有点像'||'在重击中。如果第一个是 false 或 null,它将执行第二个。

    [void](($contentDir = $config.contentDir) -or ($contentDir = "contents"))
    

    【讨论】:

      猜你喜欢
      • 2017-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-09
      • 2015-01-04
      • 2013-08-02
      • 1970-01-01
      • 2017-01-16
      相关资源
      最近更新 更多