PowerShell脚本块变量作用域

10

我在理解ScriptBlock内的作用域时遇到了一些困难。 我希望有一种类似闭包的系统,但我好像无法使其正常工作。

我有一个接受param并返回另一个ScriptBlockScriptBlock

$sb1 = {
    Param($Message1);
    Write-Host $Message1;
    {
        Param($Message2);
        Write-Host ($Message1 + " " + $Message2);
    }
}
为了获取内部的 ScriptBlock,我可以使用 $sb1 并调用 $sb2 = & $sb1 -Message1 "Message1"。这会输出 Message1,因此我们知道参数已经绑定。

现在我可以使用 & $sb2 -Message2 "Message2" 来调用 $sb2。我本来期望会输出 Message1 Message2,但实际上它只输出了 Message2

有没有办法访问 $Message1 变量?我不能使用局部或脚本变量,因为内部的脚本块会有不同的 $Message1 实例。

这是实际 shell 的输出:

PS C:\> $h1 = { Param($Message1); Write-Host $Message1; { Param($Message2); Write-Host ($Message1 + " " + $Message2); } }
PS C:\> $h2 = & $h1 -Message1 "Message1"
Message1
PS C:\> $h2
 Param($Message2); Write-Host ($Message1 + " " + $Message2);
PS C:\> & $h2 -Message2 "Message2"
 Message2

我会更新问题,告诉大家我实际运行的是什么。虽然非常相似。 - wensveen
啊,错过了返回值的赋值。好的,现在明白了 :) - Joey
1个回答

12

你需要明确地创建一个闭包

$sb1 = {
    Param($Message1);
    Write-Host $Message1;
    {
        Param($Message2);
        Write-Host ($Message1 + " " + $Message2);
    }.GetNewClosure()
}

它对我有效:

PS> $2 = & $sb1 One
One
PS> & $2 Two
One Two

好的,哇。那完全有道理。我从来不知道 ScriptBlock 实际上有一个 GetNewClosure 方法。大多数语言对于闭包并不是那么明确 :) - wensveen
有选择的权利有时候是很好的。我写过一些脚本,其中我使用了脚本块来访问我知道存在的变量,而拥有闭包会很烦人。但是,通常要么是自动的,要么根本不支持 :-) - Joey
我也不知道。不错! - Martin Brandl
我必须承认,这是我在PowerShell中看到的第一个柯里化实例。甚至从未想过要这样做 :-) - Joey

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接