当函数调用自身时,这称为“递归”。当脚本想要遍历文件系统的一部分时,你经常可以看到这种技术:一个函数处理文件夹内容,当它遇到一个子文件夹时,它会调用自己。
递归可能很强大,但它很难调试并且可能很危险,因为当你犯错误时,你最终会陷入无休止的循环。此外,当递归深度过高时,始终存在堆栈溢出的风险。
许多通常需要递归的任务也可以通过使用“队列”来设计:当你的代码遇到一个新任务时,新任务不是再次调用自身,而是被放置在队列中,一旦初始任务完成,队列中剩下的任何事情都会被处理。
有一个简单的示例,它遍历了整个驱动器 C:\,但不使用递归。相反,您可以看到运行中的队列:
# get a new queue
[System.Collections.Queue]$queue = [System.Collections.Queue]:: new()
# place the initial search path(s) into the queue
$queue.Enqueue('c:\')
# add as many more search paths as you need
# they will eventually all be traversed
#$queue.Enqueue('D:\')
# while there are still elements in the queue...
while ($queue.Count -gt 0)
{
# get one item off the queue
$currentDirectory = $queue.Dequeue()
try
{
# find all subfolders and add them to the queue
# a classic recurse approach would have called itself right here
# this approach instead pushes the future tasks just onto
# the queue for later use
[IO.Directory]::GetDirectories($currentDirectory) | ForEach-Object {
$queue.Enqueue($_)
}
}
catch {}
try
{
# find all files in this folder with the given extensions
[IO.Directory]::GetFiles($currentDirectory, '*.psm1' )
[IO.Directory]::GetFiles($currentDirectory, '*.ps1' )
}
catch{}
}