以下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
以上输出是
PSVersion 3.0
In block x=4
in printx: x=3
In closure x=1
in printx: x=4
大部分输出对我有意义:
脚本块输出In block x=4
,因为其父作用域是runblock
函数。 printx
函数输出x=3
,因为其父作用域是脚本块作用域。
关闭输出In closure x=1
,因为$x
调用捕获了GetNewClosure
的值。一切如预期。
BUT:
从闭包中调用printx
输出in printx: x=4
。因此printx
执行的范围不受$x = 3
的闭包范围的影响。
对我来说,从普通脚本块调用的函数确实可以看到脚本块作用域中的变量,但是从闭包中调用的函数看不到闭包中的变量,这似乎很奇怪。
答案 0 :(得分:8)
请考虑以下代码:
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
打印:
Closure $a=1
Closure $b=1
Print $a=3
Print $b=2
图片1:您从全局范围开始,您可以在其中定义一些变量
图片2 GetNewClosure()
创建新模块并将变量复制到其中。 (红色箭头显示父范围关系)
图3:您更改了变量的值。模块范围不受影响。
图片4:函数Run
被调用。它创建局部变量$a
。 (蓝色箭头显示呼叫方向)
图片5: $SB
脚本块被调用。脚本块绑定到模块会话状态,因此您转移到它
图片6:函数Print
已调用。函数绑定到全局会话状态,因此返回到它