MethodHandles.Loop(MethodHandle[][]) 方法
定義
重要
部分資訊涉及發行前產品,在發行之前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。
構造一個方法柄,代表一個包含多個迴圈變數的方法柄,每次迭代都會更新並檢查這些變數。
[Android.Runtime.Register("loop", "([[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;", "", ApiSince=33)]
public static Java.Lang.Invoke.MethodHandle? Loop(params Java.Lang.Invoke.MethodHandle[][]? clauses);
[<Android.Runtime.Register("loop", "([[Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/MethodHandle;", "", ApiSince=33)>]
static member Loop : Java.Lang.Invoke.MethodHandle[][] -> Java.Lang.Invoke.MethodHandle
參數
- clauses
- MethodHandle[][]
一組遵循上述規則的 S 陣列(4-元組 MethodHandle)。
傳回
一個方法的處理柄,體現了由參數定義的迴圈行為。
- 屬性
備註
構造一個方法柄,代表一個包含多個迴圈變數的方法柄,每次迭代都會更新並檢查這些變數。 當迴圈因其中一個謂詞而終止時,會執行對應的終結子,並傳遞迴圈的結果,即所產生的句柄的回傳值。
直觀上,每個迴圈由一個或多個「子句」組成,每個子句指定一個局部 <的 em>迭代變數</em> 和/或一個迴圈出口。 每次迴圈迭代都會依序執行每個子句。 子句可以選擇性地更新其迭代變數;它也可以選擇性地執行測試和條件迴圈退出。 為了以方法句柄來表達此邏輯,每個子句將指定最多四個獨立動作:ul>li em init:</em> 迴圈執行前,初始化一個型V別為 的迭代變數v。>><<<
<li><em step:</em> 當子句執行時,迭代變數 v>的更新步驟。
<li><em>pred:</em> 當子句執行時,測試 for 的謂詞執行會退出。
<li><em>fini:</em> 如果某個子句導致迴圈退出,則執行終結子以計算迴圈的回傳值。
</ul> 所有迭代變數類型的完整序列,依子句順序,將以 表示 (V...)為 。 這些值本身會是 (v...)。 當我們談論「參數清單」時,通常指的是型別,但在某些情境(描述執行時)清單會是實際值。
根據某些規則,部分子句部分可省略,並在此情況下提供有用的預設行為。 詳細說明請見下方。
<em>參數處處可選:</em> 每個子句函數都允許但非必須接受每個迭代變數 v的參數。 例外是初始化函式無法取任何 v 參數,因為執行初始化函式時這些值尚未計算。 任何子句函數都可能忽略其有權取的任何參數後續子序列。 事實上,任何子句函數都可以完全不接受參數。
<em>迴圈參數:</em> 一個子句函式可能會取用它有權擁有的所有迭代變數值,在這種情況下,它也可能使用更多尾隨參數。 這些額外值稱為 <em>迴圈參數</em>,其型別與值以 (A...)(a...)和 表示。 這些參數成為產生迴圈的參數,並在迴圈執行時提供。 (由於初始化函數不接受迭代變數 v,任何初始化函數的參數自動成為迴圈參數 a。)與迭代變數相同,子句函式被允許但非強制接受迴圈參數。 這些迴路參數作為整個迴路中可見的迴圈不變值。
<em>參數無所不在可見:</em> 每個非初始化子句函式都允許觀察整個迴圈狀態,因為它可以傳遞完整的 (v... a...) 目前迭代變數值與輸入迴圈參數清單。 初始化函數可觀察初始迴圈前狀態,形式為 (a...)。 大多數子句函數不需要所有這些資訊,但它們會以形式上與之連結,就像 。#dropArguments 「astar」>更具體地說,我們用符號(V*)表示完整序列(V...)的任意前綴(同理,對 (v*)、 (A*)(a*))。 在此符號中,初始化函數參數列表的一般形式為 (A*),非初始化函數參數列表的一般形式為 (V*) 或 (V... A*)。
<em>檢查子句結構:</em> 給定一組子句,會進行多項檢查與調整以連接迴圈的所有部分。 以下步驟將詳細說明。 在這些步驟中,每次出現「必須」字,都對應 IllegalArgumentException 一個位置,若輸入迴圈組合器未達成所需約束,將被丟棄。
<em>有效相同的序列:</em> 「effid」參數>列表A定義<為 em>與另一個參數列表B有效相同</em>,若 BA 與 相同,或 A 較短且 在適當前綴 下B相同。 當談論無序參數列表集合時,我們說該集合整體上「實質相同」,若該集合包含最長的列表,且該集合的所有成員與該最長列表實質相同。 例如,任何形式的 (V*) 類型序列集合實際上是相同的,若加入更多此類序列 (V... A*) ,情況亦同。
<em>步驟0:確定子句結構。</em><ol type=“a”<>li>子句陣列(型MethodHandle[][]別 )必須是非-null,且至少包含一個元素。
<li>子句陣列不得包含 null超過 4 個元素的 s 或子陣列。
<短於四個元素的子>句則視為被元素填充 null 至長度為四。 填充是透過在陣列中附加元素來實現的。
<包含所有 nulls 的 li>子句被忽略。
<li>每個子句被視為四個函數元組,分別稱為「init」、「step」、「pred」和「fini」。
</ol>
<em>步驟 1A:確定迭代變數類型 (V...)。</em><ol 類型=“a”><li>每個子句的迭代變數類型是透過子句的初始化與步回傳類型決定的。
<如果>兩個函數都省略,則對應子句void 的迭代變數(用 作為表示的類型)。 若省略其中一項,另一項回傳型別定義子句的迭代變數型別。 若兩者皆有,則共同回傳類型(必須相同)定義子句的迭代變數類型。
<li>形成返回類型列表(依子句順序),省略所有 的 void出現。
<li>這個類型列表稱為「迭代變數類型」((V...))。
</ol>
<em>步驟 1B:確定迴路參數(A...)。</em><ul<>li>檢視並收集初始化函數參數列表(形式(A*)為 )。
<在>移除迭代變數類型後,檢查並收集步驟參數、pred 和 fini 參數列表的後綴。 (它們必須有 (V... A*); (A*) 只收集零件。) <li>請勿從步進、pred 及 fini 參數列表中收集未以所有迭代變數類型開頭的後綴。 (這些類型會在第二步檢查,連同所有子句函式類型。) <李>省略的子句功能則被忽略。 (等價地,它們被視為參數列表為空。) <李>所有收集的參數清單必須實際上完全相同。
<li>最長的參數列表(必然唯一的)稱為「外部參數列表」((A...))。
<如果>不存在這樣的參數列表,則外部參數列表即為空序列。
<li>由迭代變數類型接外部參數類型組成的組合列表稱為「內部參數列表」。
</ul>
<em>步驟 1C:確定迴路回傳類型。</em><ol type=“a”><li>檢視fini函數返回類型,忽略遺漏的fini函數。
<如果>沒有fini函數,迴圈回傳類型為 void。
<li>否則,fini 函數的共同回傳類型 R (其返回類型必須相同)定義了迴圈回傳類型。
</ol>
<em>步驟 1D:檢查其他類型。</em><ol type=“a”><li>必須至少有一個未被遺漏的預置函數。
<li>每個未被省略的 pred 函數必須有一個 boolean 回傳型。
</ol>
<em>步驟2:確定參數清單。</em><ol 類型=“a”><li>所產生迴圈句柄的參數列表即為外部參數列表 (A...)。
<li>初始化函數的參數列表將調整為外部參數列表。 (請注意,他們的參數列表已經與此列表實際上完全相同。) <李>每個未遺漏、非初始化(步進、pred 和 fini)函式的參數清單必須與內部參數列表 (V... A...)實質上相同。
</ol>
<em>步驟3:填補遺漏的函數。</em><ol 類型=“a”><li>如果省略了初始化函式,請使用子句的迭代變數類型 #empty 預設值。
<li>若省略階梯函數,請使用子句迭代變數類型的 #identity 單位函數;在前一子句的非void 迭代變數的單位函數參數前插入刪除的參數。 (這將使迴圈變數變成局部迴圈不變量。) <李>若省略預留函數,則使用常數 true 函數。 (就此條款而言,這將讓迴圈繼續下去。注意此時對應的fini函數無法達成。) <李>若省略 fini 函數,請使用迴圈回傳類型 #empty 預設值。
</ol>
<em>步驟 4:補上缺少的參數型別。</em><ol type=“a”><li>此時,每個初始化函數參數列表實際上與外部參數列表 (A...)相同,但有些列表可能更短。 對於每個帶有短參數清單的初始化函式,請填充清單末端。
<li>此時,每個非初始化函數的參數列表實際上與內部參數列表 (V... A...)相同,但有些列表可能更短。 對於每個非初始化且參數清單很短的函式,請填充清單末端。
<li>參數列表會被 #dropArgumentsToMatch(MethodHandle, int, List, int) 填充,刪除未使用的尾隨參數。
</ol>
<em>最後觀察。</em><ol type=“a”><li>經過這些步驟後,所有子句都已透過提供省略的函數和參數進行調整。
<li>所有初始化函數都有共同的參數類型列表 (A...),最終迴圈的 handle 也會有這個列表。
<li>所有fini函數都有共同的回傳型 R態,最終迴圈的句柄也會有。
<li>所有非初始化函式都有共同的參數類型列表 (V... A...),包含(非)void迭代變數,後 V 接迴圈參數。
<Li>每對初始值與步進函數在其回傳類型 V上一致。
<每個>非初始化函數都能觀察所有迭代變數的當前值 (v...) 。
<Li>每個函數都能觀察到所有迴圈參數的輸入值 (a...) 。
</ol>
<EM>範例。</em> 根據上述步驟 1A,組合 loop 子具有以下性質: <ul><li>給定 N 子句 Cn = {null, Sn, Pn} ,且 n = 1..N。
<li>假設謂詞句柄 Pn 要麼 null 是 或 沒有參數。 (只要有一個Pn必須是非-null。) <li>假設階梯把Sn手具有某個常數 X>=N的簽名 (B1..BX)Rn。
<li>假設 Q 是非空型態 Rn的數量,而 (V1...VQ) 是這些類型的序列。
<李>,一定是 Vn == Bn 因為 n = 1..min(X,Q)。
<li>參數類型 Vn 將被解釋為迴圈-局部狀態元素 (V...)。
<li>剩餘的類型 BQ+1..BX (若 Q<X)將決定結果迴圈手柄的參數類型 (A...)。
</ul> 在這個例子中,迴圈的處理參數 (A...) 是從階梯函數推導出來的,這很自然,因為大部分迴圈運算都在步中進行。 對於某些迴圈,計算負擔可能在 pred 函數中最重,因此 pred 函數可能需要接受迴圈參數值。 對於具有複雜退出邏輯的迴圈,fini 函數可能需要接受迴圈參數;同樣地,對於具有複雜輸入邏輯的迴圈,初始化函數需要額外參數。 因此,決定這些參數的規則在所有子句部分中盡可能對稱。 一般而言,迴圈參數作為整個迴圈中的共同不變值,而迭代變數則作為共同變體值,或(若沒有階梯函數)作為內部迴圈不變的暫時值。
<em>迴圈執行。</em><ol 類型=“a”><li>當迴圈被呼叫時,迴圈的輸入值會儲存在本地值中,並傳遞給每個子句函式。 這些局部是環不變的。
<li>每個初始化函數依子句順序執行(傳遞 (a...)外部參數),非void 值則儲存為(作為迭代變數 (v...))到本地。 這些局部節點會是環路變化的(除非其步數如前所述是單位函數)。
<li>所有函式執行(init 函式除外)都會被傳遞內部參數清單,包含非void 迭代值 (v...) (依子句順序)以及迴圈輸入 (a...) (依參數順序)。
<li>接著,step 和 pred 函數依子句順序執行(pred 前的步驟),直到 pred 函數返回 false。
<li>步進函數呼叫的非void 結果用於更新迴圈變數序列 (v...) 中的對應值。 更新後的值會立即對所有後續函式呼叫可見。
<如果>pred 函數返回 false,則呼叫對應的 fini 函數,並從整個迴圈返回結果值(型別 R)。
<如果>所有 pred 函數總是回傳為真,則不會呼叫任何 fini 函數,且迴圈除了拋出例外外無法退出。
</ol>
<電磁使用>技巧。</em><ul><li>雖然每個階梯函數會接收 em>all</em> 迴圈變數的當前值<,但有時階梯函數只需觀察自身變數的當前值。 在這種情況下,階梯函數可能需要明確 #dropArguments 刪除所有前置迴圈變數。 這需要用像 dropArguments(step, 0, V0.class, ...)這樣的表達式來標示它們的類型。
<li>迴圈變數不一定必須變化;它們可以是迴圈不變的。 子句可以透過適當的初始化函式建立迴圈不變量,且沒有步驟、pred 或 fini 函數。 這對於將輸入迴圈參數「接線」到相鄰迴圈變數的步躍或 pred 函數中可能很有用。
<如果>某些子句函數是實例上的虛擬方法,該實例本身可以方便地被放入初始不變迴圈「變數」中,使用像 new MethodHandle[]{identity(ObjType.class)} 這樣的初始子句。 在這種情況下,實例參考將是第一個迭代變數的值,且將虛擬方法作為子句部分會很簡單,因為所有方法都會取一個與該值相符的前置實例參考。
</ul>
以下是產生迴圈句柄的偽程式碼。 如前所述, V 和 v 代表迴圈變數的型別與值; A 和 a 代表傳遞給整個迴圈的參數;是 R 所有終結子以及結果迴圈的共同結果型態。
<引用>
{@code
V... init...(A...);
boolean pred...(V..., A...);
V... step...(V..., A...);
R fini...(V..., A...);
R loop(A... a) {
V... v... = init...(a...);
for (;;) {
for ((v, p, s, f) in (v..., pred..., step..., fini...)) {
v = s(v..., a...);
if (!p(v..., a...)) {
return f(v..., a...);
}
}
}
}
}
</blockquote> 請注意,參數型別已(V...)(A...)擴充至完整長度,儘管個別子句函式可能忽略全部。 如前所述,缺失參數會被填補,就像由 #dropArgumentsToMatch(MethodHandle, int, List, int)。
新增9。
的 java.lang.invoke.MethodHandles.loop(java.lang.invoke.MethodHandle[]...)Java 檔。
本頁部分內容為基於 Open Source Project 所創建與分享的作品,並依授權條款所描述的使用進行修改。