2016-11-30 73 views
2

我正在学习使用PowerShell编写脚本,并且我发现这个代码可以帮助我处理项目示例来自Is there a one-liner for using default values with Read-Host?

$defaultValue = 'default' 

$prompt = Read-Host "Press enter to accept the default [$($defaultValue)]" 

$prompt = ($defaultValue,$prompt)[[bool]$prompt] 

我想我明白,$prompt = ($defaultValue,$prompt)是创建一个两元素数组,而且[bool]部分迫使$prompt数据类型为布尔值,但我不明白的代码第三行不作为一个整体。

回答

2

铸造$prompt[bool]产生取决于变量是否是空的或$true$false的值($null或空字符串两者成为$false)否(非emtpy字符串成为$true)。

[bool]''   → $false 
[bool]'something' → $true

使用在索引操作者布尔值,则隐式连铸值的整数,其中$false变为0并且$true变为1,因此选择所述阵列的所述第一或第二元件。

[int]$false → 0 
[int]$true → 1
($defaultValue,$prompt)[0] → $defaultValue 
($defaultValue,$prompt)[1] → $prompt
4

这是一个常见的编程模式:

if (user entered a price) 
{ 
    price = user entered value 
} 
else 
{ 
    price = default value 
} 

而且,因为这是很常见的,也是长篇大论,有些语言有特殊ternary operator编写所有的代码更简洁并一次性为“此值或该值”分配一个变量。例如在C#中,你可以写:

price = (user entered a price) ? (user entered value) : (default value) 
# var = IF [boolean test] ? THEN (x)   ELSE (y) 

?分配(x)如果测试结果是真,并且(y)如果测试是假的。

在Python中,它写道:

price = (user entered value) if (user entered a price) else (default value) 

而且在PowerShell中,它写道:

# you can't have a ternary operator in PowerShell, because reasons. 

呀。没有好的短代码模式允许。

但是你可以做什么,是滥用数组索引(@('x', 'y')[0] is 'x'@('x', 'y')[1] is 'y'和),并写丑陋和混乱的代码高尔夫行:

$price = ($defaultValue,$userValue)[[bool]$UserEnteredPrice] 

# var (x,y) is an array   $array[ ] is array indexing 
     (0,1) are the array indexes of the two values 

            [bool]$UserEnteredPrice casts the 'test' part to a True/False value 
            [True/False] used as indexes into an array indexing makes no sense 
                so they implicitly cast to integers, and become 0/1 

# so if the test is true, the $UserValue is assigned to $price, and if the test fails, the $DefaultValue is assigned to price. 

它就像一个三元运算符,除了它的混乱和丑陋的,在某些情况下,如果通过评估两个数组表达式而不考虑选择哪一个(不同于真实的?运算符),那么它将会让你绊倒。


编辑:我真的应该补充的是一个PowerShell的形式,我更喜欢 - 你可以分配直接在PowerShell中if测试的结果和做到:

$price = if ($userValue) { $userValue } else { $DefaultValue } 

# -> 

$prompt = if ($prompt) { $prompt } else { $DefaultValue } 
+0

感谢您的详细解答和其他编程语言的信息。 – Cliff

0

补充的给出了很好的答案by Ansgar Wiechersby TessellatingHeckler

It would be grea牛逼如果的PowerShell已经为ternary conditionalsnull-coalescing,如如下(在这个问题适用于例子)运营商:

# Ternary conditional 
# Note: does NOT work in PowerShell as of PSv5.1 
$prompt = $prompt ? $prompt : $defaultValue 

# Or, more succinctly, with null coalescence: 
# Note: does NOT work in PowerShell as of PSv5.1 
# (Note: This example assumes that $prompt will be $null in the default 
#  case, whereas the code in the question actually assigns the 
#  empty string to $prompt if the user just presses Enter.) 
$prompt = $prompt ?? $defaultValue 

不幸的是,这些表现力的结构是(仍然)不PowerShell中的一部分,它似乎PowerShell团队进入了一段延续期,在撰写本文时已经持续了将近十年:

在微软,“出货就是选择”。我们非常失望的一件事是无法在V1.0中发布,这是一个三元运算符。

PowerShell Team blog post月29日2006年12月

就在同博客中提供权宜之计在功能的形式(不完全)模拟这些运营商。

然而,试图“修复”一门语言总是很棘手的事情,所以我们希望有一天能有一个适当的实施。

下面是适应从博客文章的功能版本的相关别名定义,其使用则允许以下解决方案:

# Ternary conditional - note how the alias must come *first* 
# Note: Requires the function and alias defined below. 
$prompt = ?: $prompt $prompt $defaultValue 

# Or, more succinctly, with null coalescence - note how the alias must come *first* 
# Note: Requires the function and alias defined below. 
$prompt = ?? $prompt $defaultValue 

源代码

注意,实际功能相当短;这是基于评论的帮助,使这个清单冗长。

Set-Alias ?: Invoke-Ternary -Option AllScope 
<# 
.SYNOPSIS 
Emulation of a ternary conditional operator. 

.DESCRIPTION 
An emulation of the still-missing-from-the-PS-language ternary conditional, 
such as the C-style <predicate> ? <if-true> : <if-false> 

Because a function is used for emulation, however, the function name must 
come first in the invocation. 

If you define a succinct alias, e.g., set-alias ?: Invoke-Ternary, 
concise in-line conditionals become possible. 

To specify something other than a literal or a variable reference, pass a 
script block for any of the tree operands. 
A predicate script block is of necessity always evaluated, but a script block 
passed to the true or false branch is only evaluated on demand. 

.EXAMPLE 
> Invoke-Ternary { 2 -lt 3 } 'yes' 'no' 

Evaluates the predicate script block, which outputs $true, and therefore 
selects and outputs the true-case expression, string 'yes'. 

.EXAMPLE 
> Invoke-Ternary $false { $global:foo = 'bar' } { Get-Date } 

Outputs the result of executing Get-Date. 
Note that the true-case script block is NOT evaluated in this case. 

.NOTES 
Gratefully adapted from http://blogs.msdn.com/powershell/archive/2006/12/29/dyi-ternary-operator.aspx 
#> 
function Invoke-Ternary 
{ 
    [CmdletBinding()] 
    param($Predicate, $Then, $Otherwise = $null) 

    if ($(if ($Predicate -is [scriptblock]) { & $Predicate } else { $Predicate })) { 
    if ($Then -is [ScriptBlock]) { & $Then } else { $Then } 
    } else { 
    if ($Otherwise -is [ScriptBlock]) { & $Otherwise } else { $Otherwise } 
    } 
} 


Set-Alias ?? Invoke-NullCoalescence -Option AllScope 
<# 
.SYNOPSIS 
Emulation of a null-coalescence operator. 

.DESCRIPTION 
An emulation of a null-coalescence operator such as the following: 
<expr> ?? <alternative-expr-if-expr-is-null> 

Because a function is used for emulation, however, the function name must 
come first in the invocation. 

If you define a succinct alias, e.g., set-alias ?? Invoke-NullCoalescence, 
concise in-line null-coalescing becomes possible. 

To specify something other than a literal or a variable reference, pass a 
script block for any of the two operands. 
A first-operand script block is of necessity always evaluated, but a 
second-operand script block is only evaluated on demand. 

Note that only a true $null value in the first operand causes the second 
operand to be returned. 

.EXAMPLE 
> Invoke-NullCoalescence $null '(empty)' 

Since the first operand is $null, the second operand, string '(empty)', is 
output. 

.EXAMPLE 
> Invoke-NullCoalescence '' { $global:foo = 'bar' } 

Outputs the first operand, the empty string, because it is not $null. 
Note that the second-operand script block is NOT evaluated in this case. 

.NOTES 
Gratefully adapted from http://blogs.msdn.com/powershell/archive/2006/12/29/dyi-ternary-operator.aspx 
#> 
function Invoke-NullCoalescence 
{ 
    [CmdletBinding()] 
    param($Value, $Alternative) 

    if ($Value -is [scriptblock]) { $Value = & $Value } 

    if ($null -ne $Value) { 
    $Value 
    } else { 
    if ($Alternative -is [ScriptBlock]) { & $Alternative } else { $Alternative } 
    } 
} 
相关问题