解释从PowerShell闭包调用的函数的范围

Joh*_*ees 2 powershell closures scriptblock

以下PowerShell代码显示从闭包调用的函数的意外作用域行为.你能解释一下这是"按设计"还是缺陷?

function runblock($block) {
    $x = 4
    & $block
}

function printx() {
    "  in printx: x=" + $x
}

"PSVersion $($PSVersionTable.PSVersion)"

$x = 1
$b = {"In block x=" + $x ; $x = 3 ; printx}
$x = 2
runblock $b

$x = 1
$b = {"In closure x=" + $x ; $x = 3 ; printx}.GetNewClosure()
$x = 2
runblock $b
Run Code Online (Sandbox Code Playgroud)

以上输出是

PSVersion 3.0
In block x=4
  in printx: x=3
In closure x=1
  in printx: x=4
Run Code Online (Sandbox Code Playgroud)

大部分输出对我有意义:

脚本块输出,In block x=4因为其父作用域是runblock函数.该printx函数输出x=3自它的父范围是脚本块范围.

闭包输出In closure x=1因为$x通过GetNewClosure调用捕获的值.一切如预期.

但是:printx关闭输出的调用in printx: x=4.因此,在其中printx执行的范围不受闭包范围的影响$x = 3.

对我来说,从普通脚本块调用的函数确实可以看到脚本块作用域中的变量,但是从闭包中调用的函数看不到闭包中的变量.

use*_*407 9

考虑以下代码:

function Run {
    param($ScriptBlock)
    $a = 3
    # Picture 4
    & $ScriptBlock
}
function Print {
    # Picture 6
    "Print `$a=$a"
    "Print `$b=$b"
}
$a = 1
$b = 1
# Picture 1
$SB = {
    # Picture 5
    "Closure `$a=$a"
    "Closure `$b=$b"
    Print
}.GetNewClosure()
# Picture 2
$a = 2
$b = 2
# Picture 3
Run $SB
Run Code Online (Sandbox Code Playgroud)

它打印:

Closure $a=1
Closure $b=1
Print $a=3
Print $b=2
Run Code Online (Sandbox Code Playgroud)

图1:从全局范围开始,您可以在其中定义一些变量.
图片1
图2: GetNewClosure()创建新模块并将变量复制到它.(红色箭头显示父范围关系)
图2
图3:你改变了变量的值.模块范围不受影响.
图3
图4:Run调用的函数.它创建局部变量$a.(蓝色箭头显示呼叫方向)
图4
图5: $SB调用脚本块.脚本块绑定到模块会话状态,因此您转移到它.
图5
图6:Print调用的函数.函数绑定到全局会话状态,因此返回到它.
图6