$prompt = ($defaultValue,$prompt)[[bool]$prompt] - 在 PowerShell 中模拟三元条件
$prompt = ($defaultValue,$prompt)[[bool]$prompt] - emulating a ternary conditional in PowerShell
我正在学习使用 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
数据类型强制为布尔值,但我不明白这第三行代码作为一个整体做了什么。
将 $prompt
转换为 [bool]
会产生 $true
或 $false
的值,具体取决于变量是否为空($null
或空字符串都变为$false
) 或不是(非空字符串变为 $true
)。
[bool]'' → $false
[bool]'something' → $true
然后在索引运算符中使用该布尔值,然后将该值隐式转换为整数,其中 $false
变为 0,$true
变为 1,从而选择数组的第一个或第二个元素。
[int]$false → 0
[int]$true → 1
($defaultValue,$prompt)[0] → $defaultValue
($defaultValue,$prompt)[1] → $prompt
这是一个常见的编程模式:
if (user entered a price)
{
price = user entered value
}
else
{
price = default value
}
因为这很常见,也很啰嗦,所以一些语言有一个特殊的 ternary operator
来更简洁地编写所有代码,并一次性将一个变量分配给 "this value or that value"。例如在 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 }
为了补充 and :
给出的很好的答案
它会很棒 如果 PowerShell 有 ternary conditionals and null-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 团队已经进入了一个长期的失望期,在撰写本文时已经持续了将近十年:
At Microsoft, “to ship is to choose”. One of the things we were very disappointed in not being able to ship in V1.0 is a ternary operator.
来自 PowerShell Team blog post 2006 年 12 月 29 日。
同一个博客 post 以 函数 的形式提供权宜之计,(不完美地) 模拟 这些运算符。
然而,尝试 "fix" 一种语言总是棘手的事情,所以让我们希望有一天能够正确实施。
以下是来自博客 post 的函数的改编版本以及关联的别名定义,使用它们可以实现以下解决方案:
# 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 }
}
}
我正在学习使用 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
数据类型强制为布尔值,但我不明白这第三行代码作为一个整体做了什么。
将 $prompt
转换为 [bool]
会产生 $true
或 $false
的值,具体取决于变量是否为空($null
或空字符串都变为$false
) 或不是(非空字符串变为 $true
)。
[bool]'' → $false [bool]'something' → $true
然后在索引运算符中使用该布尔值,然后将该值隐式转换为整数,其中 $false
变为 0,$true
变为 1,从而选择数组的第一个或第二个元素。
[int]$false → 0 [int]$true → 1
($defaultValue,$prompt)[0] → $defaultValue ($defaultValue,$prompt)[1] → $prompt
这是一个常见的编程模式:
if (user entered a price)
{
price = user entered value
}
else
{
price = default value
}
因为这很常见,也很啰嗦,所以一些语言有一个特殊的 ternary operator
来更简洁地编写所有代码,并一次性将一个变量分配给 "this value or that value"。例如在 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 }
为了补充
它会很棒 如果 PowerShell 有 ternary conditionals and null-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 团队已经进入了一个长期的失望期,在撰写本文时已经持续了将近十年:
At Microsoft, “to ship is to choose”. One of the things we were very disappointed in not being able to ship in V1.0 is a ternary operator.
来自 PowerShell Team blog post 2006 年 12 月 29 日。
同一个博客 post 以 函数 的形式提供权宜之计,(不完美地) 模拟 这些运算符。
然而,尝试 "fix" 一种语言总是棘手的事情,所以让我们希望有一天能够正确实施。
以下是来自博客 post 的函数的改编版本以及关联的别名定义,使用它们可以实现以下解决方案:
# 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 }
}
}