Scheme有一个短路or
,它将返回第一个非假值:
> (or 10 20 30)
10
> (or #f 20 30)
20
> (or #f)
#f
在需要之前,它不会评估其参数。
PowerShell中是否有这样的内容?
以下是它的近似值:
function or ()
{
foreach ($arg in $args) {
$val = & $arg; if ($val) { $val; break }
}
}
示例:
PS C:\> or { 10 } { 20 } { 30 }
10
示例:
PS C:\> $abc = $null
PS C:\> or { $abc } { 123 }
123
PS C:\> $abc = 456
PS C:\> or { $abc } { 123 }
456
答案 0 :(得分:6)
你可以这样做:
10, $false, 20 | ? { $_ -ne $false } | select -First 1
结果是输入列表中的第一个值不是$false
或$null
。由于$null
是PowerShell treats as $false
在比较中的值,因此上述内容应该符合您的要求。
答案 1 :(得分:3)
您正试图让PowerShell通过您的函数使用类似Scheme的语法。不要这样做。编写惯用的PowerShell。试图强迫一种语言看起来像另一种语言只会让自己变得更加困难,为错误引入很多的空间,并且会混淆%$ ^%& ^ *(无论是谁需要维护你离开后的代码。
PowerShell似乎确实发生了短路。将此代码放在ISE中并在每个函数的write-output
行上设置断点,然后启动调试器(F5):
function first () {
write-output "first"
}
function second() {
write-output "second"
}
$true -or $(first) -or $(second);
$false -or $(first) -or $(second);
$false -or $(second) -or $(first);
$true
计算结果为true(显然),因此它不会尝试处理超出该点的表达式。当倒数第二行处理时,只有first
中的断点处理。当最后一行处理时,只有second()
中的断点被击中。
答案 2 :(得分:2)
据我所知,内置的内容并不多。我认为你的功能看起来很不错。
使它成为流水线输入可能更惯用:
function or
{
foreach ($x in $input) {
$val = & $x; if ($val) { $val; break }
}
}
示例:
PS > $abc = $null
PS > { $abc },{ 123 } | or
123
PS > $abc = 456
PS > { $abc },{ 123 } | or
456
答案 3 :(得分:1)
只要你给这个函数一个好名字,我认为创建这样一个函数是完全惯用的Powershell。我要对OP的实现做一个调整就是在脚本块中传递可选:
function Select-FirstValue {
$args |
foreach { if ($_ -is [scriptblock]) { & $_ } else { $_ } } |
where { $_ } |
select -First 1
}
然后调用者只需在可能产生副作用或性能代价高昂的参数周围添加{ }
括号。
我正在使用这样的函数作为从配置文件中为param
s提供默认值的简单方法。它看起来像:
function Do-Something {
param([string]$Arg1)
$Arg1 = Select-FirstValue $Arg1 { Get-ConfigValue 'arg1' } 'default arg1 val'
[...]
}
这样,只有在用户没有传入参数时,才会尝试读取配置文件。