简体   繁体   English

什么是PowerShell ScriptBlock

[英]What exactly is a PowerShell ScriptBlock

A PowerShell ScriptBlock is not a lexical closure as it does not close over the variables referenced in its declaring environment. PowerShell ScriptBlock不是词法闭包,因为它不会关闭其声明环境中引用的变量。 Instead it seems to leverage dynamic scope and free variables which are bound at run time in a lambda expression. 相反,它似乎利用动态范围和自由变量,这些变量在运行时绑定在lambda表达式中。

function Get-Block {
  $b = "PowerShell"
  $value = {"Hello $b"}
  return $value
}
$block = Get-Block
& $block
# Hello
# PowerShell is not written as it is not defined in the scope
# in which the block was executed.


function foo {
  $value = 5
  function bar {
    return $value
  }
  return bar
}
foo
# 5
# 5 is written $value existed during the evaluation of the bar function
# it is my understanding that a function is a named scriptblock
#  which is also registered to function:

Calling GetNewClosure() on a ScriptBlock returns a new ScriptBlock which closes over the variables referenced. 在ScriptBlock上调用GetNewClosure()会返回一个新的ScriptBlock,它会关闭引用的变量。 But this is very limited in scope and ability. 但这在范围和能力上非常有限。

What is a ScriptBlock's classification? 什么是ScriptBlock的分类?

Per the docs , a scriptblock is a "precompiled block of script text." 根据文档 ,scriptblock是“预编译的脚本文本块”。 So by default you just a pre-parsed block of script, no more, no less. 因此,默认情况下,您只需要预先解析的脚本块,不多也不少。 Executing it creates a child scope, but beyond that it's as if you pasted the code inline. 执行它会创建一个子范围,但除此之外,就像您将代码内联粘贴一样。 So the most appropriate term would simply be "readonly source code." 所以最合适的术语就是“只读源代码”。

Calling GetNewClosure bolts on a dynamically generated Module which basically carries a snapshot of all the variables in the caller's scope at the time of calling GetNewClosure . 主叫GetNewClosure上的动态生成的模块,其基本上在携带呼叫的时间在呼叫者的范围内的所有变量的快照螺栓GetNewClosure It is not a real closure, simply a snapshot copy of variables. 它不是真正的闭包,只是变量的快照副本。 The scriptblock itself is still just source code, and variable binding does not occur until it is invoked. scriptblock本身仍然只是源代码,并且在调用之前不会发生变量绑定。 You can add/remove/edit variables in the attached Module as you wish. 您可以根据需要在附加的模块中添加/删除/编辑变量。

function GetSB
{
   $funcVar = 'initial copy'

   {"FuncVar is $funcVar"}.GetNewClosure()

   $funcVar = 'updated value'  # no effect, snapshot is taken when GetNewClosure is called
}

$sb = GetSB

& $sb  # FuncVar is initial copy

$funcVar = 'outside'
& $sb  # FuncVar is initial copy

$sb.Module.SessionState.PSVariable.Remove('funcVar')
& $sb  # FuncVar is outside

A PowerShell ScriptBlock is equivalent to a first-class , anonymous function . PowerShell ScriptBlock相当于一流的 匿名函数 Most of the confusion I've seen is not with ScriptBlocks, but with the function keyword. 我见过的大多数混淆不是使用ScriptBlocks,而是使用function关键字。

  • PowerShell does support function closures , however the function keyword does not. PowerShell确实支持函数闭包 ,但函数关键字却不支持。

Examples 例子

Function: 功能:

PS> function Hello {
>>      param ([string] $thing)
>>      
>>      return ("Hello " + $thing)
>>  }

PS> Hello "World"
"Hello World"

ScriptBlock: 脚本块:

PS> $HelloSB = {
>>      param ([string] $thing)
>>      
>>      return ("Hello " + $thing)
>>  }

PS> & $HelloSB "World"
"Hello World"

PS> $HelloRef = $HelloSB
PS> & $HelloRef "Universe"
"Hello Universe"

Closure: 关闭:

PS> $Greeter = {
>>      param ([string] $Greeting)
>>      
>>      return ( {
>>          param ([string] $thing)
>>          
>>          return ($Greeting + " " + $thing)
>>      }.GetNewClosure() )
>>  }

PS> $Ahoy = (& $Greeter "Ahoy")
PS> & $Ahoy "World"
"Ahoy World"

PS> $Hola = (& $Greeter "Hola")
PS> & $Hola "Mundo"
"Hola Mundo"

Although you can get around the limitation of the function keyword with the "Set-Item" cmdlet: 虽然您可以使用“Set-Item”cmdlet解决function关键字的限制:

PS> function Greeter = { ... }  # ✕ Error
PS> function Greeter { ... }.GetNewClosure()  # ✕ Error

PS> Set-Item -Path "Function:Greeter" -Value $Greeter  # (defined above)  ✓ OK
PS> $Hola = Greeter "Hola"
PS> & $Hola "Mundo"
"Hola Mundo"

The Value parameter of the "Set-Item" cmdlet can be any ScriptBlock, even one returned by another function. “Set-Item”cmdlet的Value参数可以是任何ScriptBlock,甚至是另一个函数返回的ScriptBlock。 (The "Greeter" function, for example, returns a closure, as shown above.) (例如,“Greeter”函数返回一个闭包,如上所示。)

PS> Set-Item -Path "Function:Aloha" -Value (Greeter "Aloha")
PS> Aloha "World"
"Aloha World"

Two other important points: 另外两个要点:

  • PowerShell uses dynamic scoping , not lexical scoping. PowerShell使用动态范围 ,而不是词法范围。

    A lexical closure is closed on its source-code environment, whereas a dynamic closure is closed based on the active/dynamic environment that exists when GetNewClosure() is called. 词法闭包在其源代码环境中关闭,而动态闭包基于调用GetNewClosure()时存在的活动/动态环境而关闭。 (Which is more appropriate for a scripting language .) (哪种更适合脚本语言 。)

  • PowerShell may have "functions" and "return" statements, but actually its input/output is based on streams and piping. PowerShell可能有“函数”和“返回”语句,但实际上它的输入/输出基于流和管道。 Anything written out of a ScriptBlock with the "Write-Output" or "write" cmdlet will be returned. 将返回使用“写入输出”或“写入”cmdlet从ScriptBlock写出的任何内容。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM