2016-01-26 2 views
1

Следующий код PowerShell отображает неожиданное поведение области видимости для функций, называемых замыканиями. Можете ли вы объяснить, является ли это «по дизайну» или является дефектом?Объяснить область действия функций, вызванных замыканиями 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. Все, как ожидалось.

НО: Звонок printx с выводов замыкания in printx: x=4. Таким образом, область действия, которую выполняет printx, не зависит от области действия замыкания, где $x = 3.

Мне кажется странным, что функция, вызванная из обычного блока сценария, видит переменные в области блока сценария, но функция, вызываемая из замыкания, не видит переменных в закрытии.

ответ

7

Рассмотрим следующий код:

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: отталкиваться от глобального масштаба, где вы определяете некоторые переменные.
Picture 1
Изображение 2:GetNewClosure() создать новый модуль и скопировать ему переменные. (красная стрелка показать родительская сфера отношения)
Picture 2
Изображение 3: изменить значение переменных. Объем модуля не изменяется.
Picture 3
Изображение 4: функция Run называется. Он создает локальную переменную $a. (направление синей стрелки шоу вызова)
Picture 4
Изображение 5: блок$SB скрипта называется. Блок сценария связан с состоянием сеанса модуля, поэтому вы переходите к нему.
Picture 5
Изображение 6: функция Print называется. Функция привязана к глобальному состоянию сеанса, поэтому вы возвращаетесь к ней.
Picture 6

+1

Это замечательный ответ! –

+0

Спасибо за очень четкий ответ.Ваше объяснение, безусловно, соответствует фактам, но использует термины, с которыми я не знаком. Являются ли глобальные и модульные «состояния сеанса» документированными терминами PowerShell, или они принадлежат вашему собственному изобретению? Наконец, я обновил свой вопрос, чтобы лучше сосредоточиться на реальной проблеме: поскольку PowerShell в основном динамически охвачен, кажется странным, что это прерывается для вызовов функций, сделанных из-за закрытия. Я ожидал закрытия, чтобы изменить родительскую область самого закрытия, но не повлиять на то, как работает область действия WITHIN в закрытии. –

+0

Вот объяснение закрытия и модулей http://blogs.technet.com/b/heyscriptingguy/archive/2013/04/05/closures-in-powershell.aspx – Nat