3

我可以在javascript中编写以下代码:

function sum(num1, num2) {
  return num1 + num2;
}

然后得到一个值

var someNum = sum(2,5);

我想在 Powershell 中做同样的事情,但我阅读了以下指南:

PowerShell 也知道 return 关键字;但是,它遵循不同的逻辑。通常,return 的目的是结束代码段的执行并将控制权交还给父块。

如果在 return 语句中添加参数,则该值确实会返回给调用子程序。但是,这也适用于所有其他带有输出的语句。这意味着函数中产生的任何输出都将与返回参数一起存储在变量中。

我想这样做是为了拥有纯功能。然而,它似乎在做

var someNum = sum(2,5);

完全是多余的,当我可以调用上面的函数时,在其中定义someNum,它将在全局范围内可用。

我是否遗漏了什么,或者是否可以在 Powershell 中编写不返回函数内部所有内容的纯函数?


有点切线,但这是我的实际代码:

function GetPreviousKeyMD5Hashes() {
    $query = "SELECT Name, MD5, executed FROM [AMagicDb].[dbo].cr_Scripts";

    $command = New-Object System.Data.SQLClient.SQLCommand;
    $command.Connection = $connection;
    $command.CommandText = $query;

    try {
        $reader = $command.ExecuteReader();
        while ($reader.Read()) {
            $key = $reader.GetString(1)
            $previousScripts.Add($key) | Out-Null
        }

        $reader.Close();
        Write-Output "$(Get-Date) Finished querying previous scripts"
    }
    catch {
        $exceptionMessage = $_.Exception.Message;
        Write-Output "$(Get-Date) Error running SQL at with exception $exceptionMessage"
    }
}

接着:

$previousScripts = New-Object Collections.Generic.HashSet[string];
GetPreviousKeyMD5Hashes;

我根本不清楚这段代码 - runningGetPreviousKeyMD5Hashes确实 set $previousScripts,但这对于在我之后修改它的人来说完全不清楚。我唯一的另一种选择(afaik)是将所有这些都排成一行,这也是不可读的。

4

3 回答 3

7

完全是多余的,当我可以调用上面的函数时,在其中定义 someNum ,它将在全局范围内可用。

否:函数在.作用域中执行(除非您使用.

我是否遗漏了什么,或者是否可以在 Powershell 中编写不返回函数内部所有内容的纯函数?

是:隐式输出行为仅适用于其输出既不被捕获- $var = ...- 也不被重定向-... > foo.txt

如果有语句碰巧产生你想丢弃的输出,使用$null = ...... > $null

注意:... | Out-Null原则上也可以,但通常性能会更差,尤其是在早期的 PowerShell 版本中 - 感谢TheIncorrigible1

如果您想编写状态消息而不使其成为输出的一部分,请使用Write-Hostor,最好Write-Verbose是 or,在 PSv5+, 中Write-Information,但请注意后两者需要选择加入才能在控制台中显示它们的输出。
不要Write-Output用于写入状态消息,因为它会写入成功输出流,其目的是输出数据(“返回值”)。
有关 PowerShell 输出流的更多信息,请参阅我的这个答案

因此,相当于您的 JavaScript 代码:

function sum($num1, $num2) {
  Write-Host "Adding $num1 and $num2..."  # print status message to host (console)
  $num1 + $num2 # perform the addition and implicitly output result
}

PS> $someNum = sum 1 2 # NOTE: arguments are whitespace-separated, without (...)
Adding 1 and 2...  # Write-Host output was passed through to console

PS> $someNum  # $someNum captured the success output stream of sum()
3
于 2018-08-13T19:53:07.510 回答
1

注意:Powershell 在每条语句的末尾不需要分号;仅用于分隔同一行上的多个语句。

只要有可能,最好避免在函数中更改全局状态。将输入作为参数传递,并返回输出,因此您不必拘泥于仅以一种方式使用该函数。您的示例可能如下所示:

function sum
{
    param($num1,$num2)
    return $num1+$num2
}

$somenum=sum 2 5

现在,使用 Powershell,不需要 return 语句。没有以其他方式分配、捕获、重定向或以其他方式使用的每个语句的结果都只是与返回值一起被抛出。所以我们可以简单地替换上面的 return 语句

$num1+$num2

您已经在代码中使用了它:

$previousScripts.Add($key) | Out-Null

您在哪里丢弃.Add(). 否则它将包含在返回值中。

就个人而言,我发现使用return显式标记返回值更容易阅读。在我学习的过程中,Powershell 将所有输出都放入返回中的方式给我带来了很多麻烦。

因此,我将对您的代码进行的唯一修复是:

移动$previousScripts = New-Object Collections.Generic.HashSet[string]到函数内部,使其成为本地。

添加return $previousScripts到函数的末尾。

于 2018-08-13T19:56:48.917 回答
1

我是否遗漏了什么,或者是否可以在 Powershell 中编写不返回函数内部所有内容的纯函数?

你不能一边吃蛋糕一边吃...

如果您的功能没有输出,那么它就像您想要的那样“纯粹”。如果您有输出,那也将成为回报的一部分。

您可以使用[ref]参数。例如,请参见下文。

function DoStuff([ref]$refObj)
{
    Write-Output "DoStuff: Enter"
    $refObj.Value += $(1 + 2)
    $refObj.Value += "more strings"
    Write-Output "DoStuff: Exit"
}

$refRet = @()
$allRet = DoStuff([ref]$refRet)

"allRet"
$allRet
"refRet"
$refRet

"`n`nagain"
$allRet = DoStuff([ref]$refRet)

"allRet"
$allRet
"refRet"
$refRet
于 2018-08-13T19:21:56.133 回答