2016-11-30 72 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 } 
    } 
} 
相關問題