簡體   English   中英

什么是PowerShell ScriptBlock

[英]What exactly is a PowerShell ScriptBlock

PowerShell ScriptBlock不是詞法閉包,因為它不會關閉其聲明環境中引用的變量。 相反,它似乎利用動態范圍和自由變量,這些變量在運行時綁定在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:

在ScriptBlock上調用GetNewClosure()會返回一個新的ScriptBlock,它會關閉引用的變量。 但這在范圍和能力上非常有限。

什么是ScriptBlock的分類?

根據文檔 ,scriptblock是“預編譯的腳本文本塊”。 因此,默認情況下,您只需要預先解析的腳本塊,不多也不少。 執行它會創建一個子范圍,但除此之外,就像您將代碼內聯粘貼一樣。 所以最合適的術語就是“只讀源代碼”。

主叫GetNewClosure上的動態生成的模塊,其基本上在攜帶呼叫的時間在呼叫者的范圍內的所有變量的快照螺栓GetNewClosure 它不是真正的閉包,只是變量的快照副本。 scriptblock本身仍然只是源代碼,並且在調用之前不會發生變量綁定。 您可以根據需要在附加的模塊中添加/刪除/編輯變量。

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

PowerShell ScriptBlock相當於一流的 匿名函數 我見過的大多數混淆不是使用ScriptBlocks,而是使用function關鍵字。

  • PowerShell確實支持函數閉包 ,但函數關鍵字卻不支持。

例子

功能:

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

PS> Hello "World"
"Hello World"

腳本塊:

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

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

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

關閉:

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"

雖然您可以使用“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"

“Set-Item”cmdlet的Value參數可以是任何ScriptBlock,甚至是另一個函數返回的ScriptBlock。 (例如,“Greeter”函數返回一個閉包,如上所示。)

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

另外兩個要點:

  • PowerShell使用動態范圍 ,而不是詞法范圍。

    詞法閉包在其源代碼環境中關閉,而動態閉包基於調用GetNewClosure()時存在的活動/動態環境而關閉。 (哪種更適合腳本語言 。)

  • PowerShell可能有“函數”和“返回”語句,但實際上它的輸入/輸出基於流和管道。 將返回使用“寫入輸出”或“寫入”cmdlet從ScriptBlock寫出的任何內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM