作為說明,這是一個輸出十個整數的函式。
function Foo { for($i = 0; $i -lt 10; $i ) { Write-Host Inner $i; $i; }}
當我們呼叫Foo如下時,Foo只迭代五次。這就是我們想要的。
Foo | Select-Object -First 5
當我們這樣呼叫時Foo,Foo迭代所有十次。這就是我們想要避免的。
$foo = Foo; $foo | Select-Object -First 5;
有時中間變數對于可讀性很有用。
當我們使用中間變數時,如果有的話,我們如何維護 PowerShell 一次一個處理?
根據要求,這里詳細說明了我們可能想要在現實世界中這樣做的原因。它仍然令人費解,但它理解了這個想法。以下輸出public struct受版本控制的 C# 檔案中型別的名字。
Get-ChildItem -Directory -Recurse |
Where-Object { Test-Path (Join-Path $_.FullName ".git") } |
Select-Object -ExpandProperty FullName |
Get-ChildItem -File -Recurse -Filter *.cs |
Get-Content |
Select-String "public struct" |
Select-Object -First 1;
這是一個很好的查詢,但可以說一兩個解釋變數會很有用。
$gitRepositories = Get-ChildItem -Directory -Recurse |
Where-Object { Test-Path (Join-Path $_.FullName ".git") };
$csharpFiles = $gitRepositories |
Select-Object -ExpandProperty FullName |
Get-ChildItem -File -Recurse -Filter *.cs
$structNames = $csharpFiles |
Get-Content |
Select-String "public struct" |
Select-Object -First 1;
當用 包裝時Measure-Command,第一個查詢需要 8.5 秒,第二個查詢需要幾分鐘。
uj5u.com熱心網友回復:
如果你讓你的函式成為高級函式,通過[CmdletBinding()],像這樣:
function Foo {
[CmdletBinding()]
param()
for($i = 0; $i -lt 10; $i ) {
Write-Host Inner $i; $i;
}
}
然后您可以訪問自動引數-OutVariable,現在您可以執行以下操作:
Foo -OutVariable foo | Select-Object -First 5
$foo
當然,在您的示例中,您可以輕松地執行以下操作:
$foo = Foo | Select-Object -First 5
所以我不確定你到底想要什么,但我懷疑這-OutVariable更符合要求,因為它隨著管道的運行而填充。
例如:
function Foo {
[CmdletBinding()]
param()
for($i = 0; $i -lt 10; $i ) {
Write-Host Inner $i; $i;
sleep -s 2
}
}
(現在函式在每次迭代中休眠 2 秒)
如果你然后CTRLC在它的中間,$foo將包含到目前為止產生的內容。
通過進一步的評論,我想我明白你現在在追求什么:一個可以在以后列舉的函式的回傳值。這是一個列舉器。
從函式中回傳一個有兩種復雜情況:
- PowerShell 傾向于在回傳時自動“展開”(處理)這些,但您可能可以通過回傳單個元素陣列的經典技巧來解決這個問題,其中元素是列舉數。
- 在不預處理所有專案的情況下創建列舉器將取決于它的細節。
要創建列舉器,您需要創建一個繼承自IEnumerator. 你可以讓這個類做任何你想做的事情,這樣實作的復雜性就會消失。
你的函式實際上只是作為一個 PowerShell 介面來實體化和回傳這樣的東西。
class MyEnumerator : System.Collections.IEnumerator
{
hidden [int] $index;
hidden [int] $max;
hidden [int] $start;
hidden [int] $item;
MyEnumerator([int]$max, [int]$start=0) {
$this.index = -1
$this.start = $start
$this.max = $max
}
[bool] MoveNext() {
$this.index
$this.item = $this.index $this.start
# demonstration
if ($this.item -gt 7) {
throw
}
return ($this.item -le $this.max)
}
[void] Reset() {
$this.index = -1
}
[object] get_Current() {
return $this.item
}
}
function Foo ($start, $max) {
,[MyEnumerator]::new($max, $start)
}
So here in this example, I've created this enumerator class, and you can give it any start and max integer value for it to enumerate through. But I threw in a little catch in that it's hardcoded to throw an exception if the item value is greater than 7.
The function creates the enumerator and returns it (notice the unary comma for making a single element array).
So you can run this like so:
$foo = Foo 2 10
# no exception!
$foo | Select -First 5
# no exception!
This on the other hand:
$foo = Foo 2 10
$foo
# will throw
(you've attempted to enumerate through the whole thing, implicitly)
One thing you need to be aware of is that $foo is the enumerator object, and keeps state, and now you need to be responsible for that if you're trying to "re-use" it.
Example:
$foo = Foo 2 10
$foo | Select -First 5
$foo.Current
# 6
$foo | Select -First 5
# 7
# exception!
You can use $foo.Reset() to make it go back to the beginning.
Another alternative: returning a function (or just a script block) from a function.
This one won't behave as naturally as the enumerator, but it'll be easier to implement.
function Foo {
{
for($i = 0; $i -lt 10; $i ) { Write-Host Inner $i; $i; }
}
}
$foo = Foo ; & $foo | Select-Object -First 5
For this, since the return value is a script block, you'll have to execute it before piping it along.
I imagine what you were really looking for was the enumerator, but you can see that that will require some heavier lifting to implement.
uj5u.com熱心網友回復:
該代碼適用于您收集的實際物件$foo- 這是一個整數陣列 0 - 9。寫入主機將始終輸出到控制臺*。
用你的例子輸出是
Inner 0
Inner 1
Inner 2
Inner 3
Inner 4
Inner 5
Inner 6
Inner 7
Inner 8
Inner 9
0
1
2
3
4
如您所見,select-object -first 5 作業得很好,選擇了 0 - 4。
所以澄清一下,當你運行時,你的整個函式正在運行到完成
$foo = Foo
輸出 10 個寫主機陳述句。
Inner 0
Inner 1
Inner 2
Inner 3
Inner 4
Inner 5
Inner 6
Inner 7
Inner 8
Inner 9
然后Select-Object -First 5選擇 5 個物件。
$foo | Select-Object -First 5
0
1
2
3
4
* 除非重定向到另一個流
uj5u.com熱心網友回復:
Powershell 正在按照您的要求執行操作。在賦值陳述句期間,回圈已經運行了 10 次。寫主機輸出不會存盤在 $foo 變數中。這似乎是獲得所需輸出的唯一方法,在實際運行時讓 select-object 終止回圈。無論如何,寫主機輸出永遠不會進入管道。
$foo = Foo | Select-Object -First 5
Inner 0
Inner 1
Inner 2
Inner 3
Inner 4
$foo
0
1
2
3
4
1..10 | % { write-host num $_ } | select -first 5
num 1
num 2
num 3
num 4
num 5
num 6
num 7
num 8
num 9
num 10
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/328446.html
標籤:电源外壳
