Freigeben über


MethodHandles.Loop(MethodHandle[][]) Methode

Definition

Erstellt ein Methodenhandle, das eine Schleife mit mehreren Schleifenvariablen darstellt, die bei jeder Iteration aktualisiert und überprüft werden.

[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

Parameter

clauses
MethodHandle[][]

ein Array von Arrays (4 Tupel) von MethodHandles, die den oben beschriebenen Regeln entsprechen.

Gibt zurück

ein Methodenhandle, das das Schleifenverhalten verkörpert, wie durch die Argumente definiert.

Attribute

Hinweise

Erstellt ein Methodenhandle, das eine Schleife mit mehreren Schleifenvariablen darstellt, die bei jeder Iteration aktualisiert und überprüft werden. Beim Beenden der Schleife aufgrund eines der Prädikate wird ein entsprechender Finalizer ausgeführt und liefert das Ergebnis der Schleife, bei dem es sich um den Rückgabewert des resultierenden Handles handelt.

Intuitiv wird jede Schleife durch eine oder mehrere "Klauseln" gebildet, die jeweils eine lokale <em>Iterationsvariable</em> und/oder einen Schleifenausgang angeben. Jede Iteration der Schleife führt jede Klausel in der reihenfolge aus. Eine Klausel kann optional ihre Iterationsvariable aktualisieren. Optional kann sie auch einen Test und einen bedingten Schleifenausgang durchführen. Um diese Logik in Bezug auf Methodenhandles auszudrücken, gibt jede Klausel bis zu vier unabhängige Aktionen an:<ul><li><em>init:</em> Bevor die Schleife ausgeführt wird, wird die Initialisierung einer Iterationsvariable v vom Typ angegeben V. <li><em>step:</em> Wenn eine Klausel ausgeführt wird, ist ein Aktualisierungsschritt für die Iterationsvariable .v <li><em>pred:</em> Wenn eine -Klausel ausgeführt wird, wird eine Prädikatausführung auf Schleifenausgang getestet. <li><em>fini:</em> Wenn eine Klausel einen Schleifenausgang verursacht, wird der Rückgabewert der Schleife durch eine Finalizerausführung berechnet. </ul> Die vollständige Sequenz aller Iterationsvariablentypen wird in Klauselreihenfolge als (V...)notiert. Die Werte selbst sind (v...). Wenn wir von "Parameterlisten" sprechen, beziehen wir uns normalerweise auf Typen, aber in einigen Kontexten (die Ausführung beschreiben) sind die Listen von tatsächlichen Werten.

Einige dieser Klauselteile können gemäß bestimmten Regeln weggelassen werden, und in diesem Fall wird nützliches Standardverhalten bereitgestellt. Eine ausführliche Beschreibung finden Sie unten.

<em>Parameters optional everywhere:</em> Jede Klauselfunktion ist zulässig, aber nicht erforderlich, um einen Parameter für jede Iterationsvariable vzu akzeptieren. Als Ausnahme können die Initfunktionen keine v Parameter annehmen, da diese Werte noch nicht berechnet werden, wenn die Initfunktionen ausgeführt werden. Jede Klauselfunktion kann es vernachlässigen, alle nachfolgenden Untersequiden von Parametern zu übernehmen, zu deren Verwendung sie berechtigt ist. Tatsächlich kann jede Klauselfunktion überhaupt keine Argumente annehmen.

<em>Loop parameters:</em> Eine Klauselfunktion kann alle Iterationsvariablenwerte übernehmen, für die sie berechtigt ist. In diesem Fall kann sie auch weitere nachgestellte Parameter annehmen. Solche zusätzlichen Werte werden als em-Schleifenparameter<>/em> bezeichnet<, wobei ihre Typen und Werte als (A...) und (a...)notiert sind. Diese werden zu den Parametern des resultierenden Schleifenhandles, die bei der Ausführung der Schleife angegeben werden sollen. (Da Initfunktionen keine Iterationsvariablen vakzeptieren, ist jeder Parameter einer Initfunktion automatisch ein Schleifenparameter a.) Wie bei Iterationsvariablen sind Klauselfunktionen zulässig, aber nicht erforderlich, um Schleifenparameter zu akzeptieren. Diese Schleifenparameter fungieren als schleifeninvariante Werte, die über die gesamte Schleife sichtbar sind.

<em>Parameters visible everywhere:</em> Jede Non-init-Klauselfunktion darf den gesamten Schleifenzustand beobachten, da die vollständige Liste (v... a...) der aktuellen Iterationsvariablenwerte und eingehender Schleifenparameter übergeben werden kann. Die Initfunktionen können den anfänglichen Präschleifenzustand im Format (a...)beobachten. Die meisten Klauselfunktionen benötigen nicht alle diese Informationen, aber sie werden formal mit ihr verbunden, als ob mit #dropArguments. "astar"> Genauer gesagt, verwenden wir die Notation (V*) , um ein beliebiges Präfix einer vollständigen Sequenz (V...) auszudrücken (und ebenso für (v*), (A*), (a*)). In dieser Notation ist (A*)die allgemeine Form einer Init-Funktionsparameterliste, und die allgemeine Form einer Nicht-Init-Funktionsparameterliste ist (V*) oder (V... A*).

<em>Checking-Klauselstruktur:</em> Bei einer Reihe von Klauseln werden eine Reihe von Überprüfungen und Anpassungen durchgeführt, um alle Teile der Schleife zu verbinden. Sie werden in den folgenden Schritten ausführlich beschrieben. In diesen Schritten entspricht jedes Vorkommen des Worts "muss" einer Stelle, an IllegalArgumentException der ausgelöst wird, wenn die erforderliche Einschränkung durch die Eingaben zum Schleifenkombinator nicht erfüllt wird.

<em>Effektiv identische Sequenzen:</em> "effid"> Eine Parameterliste A ist definiert, um effektiv identisch<> mit einer anderen Parameterliste B zu sein<>, wenn A und B identisch ist, oder wenn A kürzer und mit dem richtigen Präfix Bidentisch ist. Wenn wir von einem ungeordneten Satz von Parameterlisten sprechen, sagen wir, dass der Satz als Ganzes "effektiv identisch" ist, wenn der Satz eine längste Liste enthält und alle Elemente der Gruppe effektiv mit dieser längsten Liste identisch sind. Beispielsweise ist jeder Satz von Typsequenzen des Formulars (V*) effektiv identisch, und dasselbe gilt für den Fall, dass weitere Sequenzen des Formulars (V... A*) hinzugefügt werden.

<em>Schritt 0: Bestimmen der Klauselstruktur.</em><ol type="a"><li>Das Klauselarray (vom Typ MethodHandle[][]) muss nicht seinnull und mindestens ein Element enthalten. <li>Das Klauselarray darf keine s- oder Unterarrays enthalten null, die länger als vier Elemente sind. <Li-Klauseln>, die kürzer als vier Elemente sind, werden so behandelt, als wären sie mit null Elementen auf die Länge vier gepolstert. Das Auffüllen erfolgt durch Anfügen von Elementen an das Array. <Li-Klauseln>mit allen nulls werden ignoriert. <li>Jede Klausel wird als vier Tupel von Funktionen behandelt, die als "init", "step", "pred" und "fini" bezeichnet werden. </Ol>

<em>Schritt 1A: Bestimmen der Iterationsvariablentypen (V...).</em><ol type="a"><li>Der Iterationsvariablentyp für jede Klausel wird mithilfe der Init- und Step-Rückgabetypen der Klausel bestimmt. <li>Wenn beide Funktionen weggelassen werden, gibt es keine Iterationsvariable für die entsprechende Klausel (void wird als Typ verwendet, um dies anzugeben). Wenn eine davon ausgelassen wird, definiert der Rückgabetyp des anderen den Iterationsvariablentyp der Klausel. Wenn beide angegeben sind, definiert der allgemeine Rückgabetyp (sie müssen identisch sein) den Iterationsvariablentyp der Klausel. <li>Bilden Sie die Liste der Rückgabetypen (in Klauselreihenfolge), und lassen Sie alle Vorkommen von weg void. <li>Diese Liste von Typen wird als "Iterationsvariablentypen" ((V...)) bezeichnet. </Ol>

<em>Schritt 1B: Bestimmen von Schleifenparametern (A...).</em><ul><li>Untersuchen und Sammeln von Init-Funktionsparameterlisten (die in der Form (A*)sind ). <li>Untersuchen und sammeln Sie die Suffixe der Parameterlisten step, pred und fini, nachdem sie die Iterationsvariablentypen entfernt haben. (Sie müssen das Formular (V... A*)haben; sammeln Sie nur die (A*) Teile.) <li>Sammeln Sie keine Suffixe aus schritt-, pred- und fini-Parameterlisten, die nicht mit allen Iterationsvariablentypen beginnen. (Diese Typen werden in Schritt 2 zusammen mit allen Klauselfunktionstypen überprüft.) <Li>Ausgelassene Klauselfunktionen werden ignoriert. (Entsprechend gelten sie als leere Parameterlisten.) <Li>Alle gesammelten Parameterlisten müssen effektiv identisch sein. <li>Die längste Parameterliste (die notwendigerweise eindeutig ist) wird als "externe Parameterliste" ((A...)) bezeichnet. <li>Wenn keine solche Parameterliste vorhanden ist, wird die externe Parameterliste als leere Sequenz betrachtet. <li>Die kombinierte Liste, die aus Iterationsvariablentypen besteht, gefolgt von den externen Parametertypen, wird als "interne Parameterliste" bezeichnet. </ul>

<em>Schritt 1C: Bestimmen des Schleifenrückgabetyps.</em><ol type="a"><li>Untersuchen Sie die Rückgabetypen der fini-Funktion, ohne ausgelassene fini-Funktionen zu ignorieren. <li>Wenn keine fini-Funktionen vorhanden sind, ist voidder Schleifenrückgabetyp . <li>Andernfalls definiert der allgemeine Rückgabetyp R der fini-Funktionen (ihre Rückgabetypen müssen identisch sein) den Schleifenrückgabetyp. </Ol>

<em>Schritt 1D: Überprüfen Sie andere Typen.</em><ol type="a"><li>Es muss mindestens eine nicht ausgelassene Pred-Funktion vorhanden sein. <li>Jede nicht ausgelassene Pred-Funktion muss über einen boolean Rückgabetyp verfügen. </Ol>

<em>Schritt 2: Bestimmen von Parameterlisten.</em><ol type="a"><li>Die Parameterliste für das resultierende Schleifenhandle ist die externe Parameterliste (A...). <li>Die Parameterliste für Initfunktionen wird an die externe Parameterliste angepasst. (Beachten Sie, dass ihre Parameterlisten bereits effektiv mit dieser Liste identisch sind.) <Li>Die Parameterliste für jede nicht ausgelassene Nicht-Init-Funktion (step, pred und fini) muss effektiv mit der internen Parameterliste (V... A...)identisch sein. </Ol>

<em>Schritt 3: Füllen Sie ausgelassene Funktionen aus.</em><ol type="a"><li>Wenn eine init-Funktion ausgelassen wird, verwenden Sie einen #empty Standardwert für den Iterationsvariablentyp der Klausel. <li>Wenn eine Schrittfunktion ausgelassen wird, verwenden Sie eine #identity Identitätsfunktion des Iterationsvariablentyps der Klausel. Fügen Sie gelöschte Argumentparameter vor dem Identitätsfunktionsparameter für die Nicht-Iterationsvariablenvoid der vorherigen Klauseln ein. (Dadurch wird die Schleifenvariable in eine lokale Schleife invariant umgewandelt.) <Li>Wenn eine Pred-Funktion ausgelassen wird, verwenden Sie eine Konstante true - Funktion. (Dadurch wird die Schleife beibehalten, was diese Klausel betrifft. Beachten Sie, dass in solchen Fällen die entsprechende fini-Funktion nicht erreichbar ist.) <Li>Wenn eine fini-Funktion ausgelassen wird, verwenden Sie einen #empty Standardwert für den Schleifenrückgabetyp. </Ol>

<em>Schritt 4: Geben Sie fehlende Parametertypen ein.</em><ol type="a"><li>An diesem Punkt ist jede Init-Funktionsparameterliste effektiv mit der externen Parameterliste (A...)identisch, aber einige Listen sind möglicherweise kürzer. Wählen Sie für jede Init-Funktion mit einer kurzen Parameterliste das Ende der Liste aus. <li>An diesem Punkt ist jede Nicht-init-Funktionsparameterliste effektiv mit der internen Parameterliste (V... A...)identisch, aber einige Listen sind möglicherweise kürzer. Für jede Nicht-Init-Funktion mit einer kurzen Parameterliste, wählen Sie das Ende der Liste aus. <li>Argumentlisten werden durch #dropArgumentsToMatch(MethodHandle, int, List, int) aufgefüllt, die nicht verwendete nachgestellte Argumente löschen. </Ol>

<em>Abschließende Beobachtungen.</em><ol type="a"><li>Nach diesen Schritten wurden alle Klauseln angepasst, indem ausgelassene Funktionen und Argumente bereitgestellt wurden. <li>Alle init-Funktionen verfügen über eine allgemeine Parametertypliste (A...), die auch das letzte Schleifenhandle aufweist. <li>Alle fini-Funktionen weisen einen gemeinsamen Rückgabetyp Rauf, den auch das letzte Schleifenhandle aufweist. <li>Alle Nicht-Init-Funktionen verfügen über eine allgemeine Parametertypliste (V... A...), der (Nicht-void) Iterationsvariablen V gefolgt von Schleifenparametern. <li>Jedes Paar von Init- und Schrittfunktionen stimmt in ihrem Rückgabetyp Vüberein. <li>Jede Nicht-Init-Funktion kann die aktuellen Werte (v...) aller Iterationsvariablen beobachten. <li>Jede Funktion kann die eingehenden Werte (a...) aller Schleifenparameter beobachten. </Ol>

<em>Beispiel.</em> Als Folge von Schritt 1A oben weist der loop Kombinator die folgende Eigenschaft auf: <ul><li>Given-Klauseln Cn = {null, Sn, PnN } mit n = 1..N. <li>Angenommen, Prädikathandles Pn sind entweder null oder haben keine Parameter. (Nur eine Pn muss nicht seinnull.) <li>Angenommen, Schritthandles Sn verfügen über Signaturen (B1..BX)Rnfür eine Konstante X>=N. <li>Angenommen, Q die Anzahl der nicht leeren Typen Rnist und (V1...VQ) die Sequenz dieser Typen ist. <li>Es muss das Vn == Bn für n = 1..min(X,Q)sein. <li>Die Parametertypen Vn werden als schleifenlokale Zustandselemente (V...)interpretiert. <li>Alle verbleibenden Typen BQ+1..BX (wenn Q<X) bestimmen die Parametertypen (A...)des resultierenden Schleifenhandles. </ul> In diesem Beispiel wurden die Schleifenhandleparameter (A...) von den Schrittfunktionen abgeleitet, was natürlich ist, wenn die meisten Schleifenberechnungen in den Schritten erfolgen. Bei einigen Schleifen kann die Berechnungslast in den Pred-Funktionen am größten sein, sodass die Pred-Funktionen möglicherweise die Schleifenparameterwerte akzeptieren müssen. Für Schleifen mit komplexer Exitlogik müssen die fini-Funktionen möglicherweise Schleifenparameter akzeptieren, und ebenso für Schleifen mit komplexer Einstiegslogik, bei denen die Initialisierungsfunktionen die zusätzlichen Parameter benötigen. Aus diesen Gründen sind die Regeln für die Bestimmung dieser Parameter so symmetrisch wie möglich, über alle Klauselteile hinweg. Im Allgemeinen funktionieren die Schleifenparameter als allgemeine invariante Werte für die gesamte Schleife, während die Iterationsvariablen als gemeinsame Variantenwerte oder (wenn keine Schrittfunktion vorhanden ist) als interne Schleifeninvariante fungieren.

<em-Schleifenausführung>.</em><ol type="a"><li>Wenn die Schleife aufgerufen wird, werden die Schleifeneingabewerte in locals gespeichert, um sie an jede Klauselfunktion zu übergeben. Diese lokalen Elemente sind invariant. <li>Jede init-Funktion wird in der Klauselreihenfolge ausgeführt (übergeben die externen Argumente (a...)), und die Nicht-Wertevoid werden (als Iterationsvariablen (v...)) in locals gespeichert. Diese lokalen Schleifen variieren (es sei denn, ihre Schritte verhalten sich wie oben erwähnt als Identitätsfunktionen). <li>Alle Funktionsausführungen (mit Ausnahme von Init-Funktionen) werden an die interne Parameterliste übergeben, die aus den Nicht-Iterationswertenvoid(v...) (in Klauselreihenfolge) und dann den Schleifeneingaben (a...) (in Argumentreihenfolge) besteht. <li>Die Funktionen step und pred werden dann in der Klauselreihenfolge (Schritt vor pred) ausgeführt, bis eine pred-Funktion zurückgibt false. <li>Das Nicht-Ergebnisvoid eines Schrittfunktionsaufrufs wird verwendet, um den entsprechenden Wert in der Sequenz (v...) von Schleifenvariablen zu aktualisieren. Der aktualisierte Wert ist sofort für alle nachfolgenden Funktionsaufrufe sichtbar. <li>Wenn eine pred-Funktion zurückgibt false, wird die entsprechende fini-Funktion aufgerufen, und der resultierende Wert (vom Typ R) wird von der Schleife als Ganzes zurückgegeben. <li>Wenn alle pred-Funktionen immer true zurückgeben, wird keine fini-Funktion aufgerufen, und die Schleife kann nur durch Auslösen einer Ausnahme beendet werden. </Ol>

<em>Tipps zur Verwendung.</em><ul><li>Obwohl jede Schrittfunktion die aktuellen Werte von <em>all</em> der Schleifenvariablen empfängt, muss eine Schrittfunktion manchmal nur den aktuellen Wert ihrer eigenen Variablen beobachten. In diesem Fall muss die Schrittfunktion möglicherweise alle vorangehenden Schleifenvariablen explizit #dropArguments löschen. Dazu müssen ihre Typen in einem Ausdruck wie erwähnt dropArguments(step, 0, V0.class, ...)werden. <Li-Schleifenvariablen>müssen nicht variieren. Sie können invariant sein. Eine -Klausel kann eine invariante Schleife durch eine geeignete init-Funktion ohne Step-, Pred- oder fini-Funktion erstellen. Dies kann hilfreich sein, um ein Argument der eingehenden Schleife mit der Schritt- oder Prädfunktion einer benachbarten Schleifenvariablen zu "verkabeln". <li>Wenn einige der Klauselfunktionen virtuelle Methoden auf einem instance sind, kann die instance selbst bequem in eine anfängliche invariante Schleife "variable" platziert werden, wobei eine anfängliche Klausel wie new MethodHandle[]{identity(ObjType.class)}verwendet wird. In diesem Fall ist der instance Verweis der erste Iterationsvariablenwert, und es ist einfach, virtuelle Methoden als Klauselteile zu verwenden, da sie alle einen führenden instance Verweis benötigen, der mit diesem Wert übereinstimmt. </ul>

Hier ist der Pseudocode für das resultierende Schleifenhandle. Wie oben dargestellt, V stellen und v die Typen und Werte von Schleifenvariablen dar, A und a stellen Argumente dar, die an die gesamte Schleife übergeben werden. Und R ist der gemeinsame Ergebnistyp aller Finalizer sowie der resultierenden Schleife. <Blockquote>

{@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> Beachten Sie, dass der Parametertyp listet (V...) und (A...) auf seine volle Länge erweitert wurde, auch wenn einzelne Klauselfunktionen möglicherweise vernachlässigen, sie alle zu übernehmen. Wie oben erwähnt, werden fehlende Parameter wie von #dropArgumentsToMatch(MethodHandle, int, List, int)ausgefüllt.

In 9 hinzugefügt.

Java-Dokumentation für java.lang.invoke.MethodHandles.loop(java.lang.invoke.MethodHandle[]...).

Teile dieser Seite sind Änderungen, die auf Arbeiten basieren, die vom Android Open Source Project erstellt und freigegeben wurden und gemäß den In Attribution License beschriebenen Begriffen verwendet werden.

Gilt für: