匿名递归函数

iRo*_*Ron 3 powershell recursion function

是否可以在 PowerShell 中创建匿名递归函数?(如果是,怎么做?)

我有一个递归对象并使用递归函数向下钻取属性,例如:

$Object = ConvertFrom-Json '
{
    "Name" : "Level1",
    "Folder" : {
        "Name" : "Level2",
        "Folder" : {
            Name : "Level3"
        }       
    }
}'

Function GetPath($Object) {
    $Object.Name
    if ($Object.Folder) { GetPath $Object.Folder }
}

(GetPath($Object)) -Join '\'

Level1\Level2\Level3
Run Code Online (Sandbox Code Playgroud)

该函数相对较小,并且只有必需的函数,因此我想直接将其作为匿名函数调用,例如:

(&{
    $Object.Name
    if ($Object.Folder) { ???? $Object.Folder }
}) -Join '\'
Run Code Online (Sandbox Code Playgroud)

这在 PowerShell 中可能吗?如果是,我如何(尽可能干净地)引用当前函数????

San*_*zon 6

不幸的是,关于这个主题的文档并不多,但您可以通过自动变量(特别是Property )执行匿名脚本块$MyInvocationScriptInfo.ScriptBlock

一个简单的例子:

& {
    param([int] $i)

    if($i -eq 10) { return $i }
    ($i++)
    & $MyInvocation.MyCommand.ScriptBlock $i
}

# Results in 0..10
Run Code Online (Sandbox Code Playgroud)

使用您当前的代码和有问题提供的 Json:

(& {
    param($s)

    $s.Name; if ($s.Folder) { & $MyInvocation.MyCommand.ScriptBlock $s.Folder }
} $Object) -join '\'

# Results in Level1\Level2\Level3
Run Code Online (Sandbox Code Playgroud)

与上面相同,但使用管道处理

($Object | & {
    process {
        $_.Name; if($_.Folder) { $_.Folder | & $MyInvocation.MyCommand.ScriptBlock }
    }
}) -join '\'
Run Code Online (Sandbox Code Playgroud)

代码多一点,但可以使用Collections.Queue递归代替递归来完成相同的任务,这可能会更有效地利用资源:

$(
    $queue = [System.Collections.Queue]::new()
    $queue.Enqueue($object)
    while($queue.Count) {
        $node = $queue.Dequeue()
        $node.Name
        if($node.Folder) { $queue.Enqueue($node.Folder) }
    }
) -join '\'
Run Code Online (Sandbox Code Playgroud)