在Powershell中显式返回

时间:2018-08-13 17:48:08

标签: powershell pure-function

我可以用javascript编写以下代码:

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

然后获取一个值

var someNum = sum(2,5);

我想在Powershell中做同样的事情,但是我读了following guide:

  

PowerShell也知道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;

这个代码对我来说一点都不清晰-运行GetPreviousKeyMD5Hashes确实设置了$previousScripts,但对于在我之后进行修改的人来说,这还不清楚。我唯一的另一种选择(afaik)是使所有这些保持一致,这也不可读。

3 个答案:

答案 0 :(得分:5)

  

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

否:函数在 child 范围中执行(除非您使用.点源它们),因此在函数内部创建或分配给它们的变量是本地

  

我是否缺少某些东西,或者有可能在Powershell中编写不返回函数内部所有内容的纯函数?

是:隐式输出行为仅适用于既没有捕获-$var = ...-也没有重定向-... > foo.txt的语句

如果有一些语句恰好会产生您要放弃的输出,请使用$null = ...... > $null

注意:... | Out-Null原则上也可以工作,但通常表现较差,尤其是在早期的PowerShell版本中,谢谢TheIncorrigible1

如果您有 个状态消息,但您不想编写它们,则不写它们,请使用Write-Host或最好使用{ {1}},或者在PSv5 +中,Write-Verbose ,尽管请注意,后两个要求选择接受才能在控制台中看到其输出。
请勿使用Write-Information来写状态消息,因为它会写入成功输出流,其目的是输出 data (“返回值”)。< br /> 有关PowerShell的输出流的更多信息,请参见我的this answer

因此,您的JavaScript代码等效于:

Write-Output

答案 1 :(得分: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

答案 2 :(得分: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