MethodHandles.Loop(MethodHandle[][]) 方法

定义

构造一个表示循环的方法句柄,其中包含多个循环变量,这些变量在每次迭代时更新和检查。

[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[][]

符合上述规则的数组(4 元组 MethodHandle)。

返回

一个方法句柄,表示由参数定义的循环行为。

属性

注解

构造一个表示循环的方法句柄,其中包含多个循环变量,这些变量在每次迭代时更新和检查。 由于谓词之一而终止循环时,将运行相应的终结器并传递循环的结果,这是生成的句柄的返回值。

直观地说,每个循环由一个或多个“子句”形成,每个循环都指定本地 <em>迭代变量</em> 和/或循环退出。 循环的每个迭代按顺序执行每个子句。 子句可以选择更新其迭代变量;它还可以选择性地执行测试和条件循环退出。 为了在方法句柄方面表达此逻辑,每个子句将指定最多四个独立操作:<ul><li><em>init:</em> 在循环执行之前,初始化类型V迭代变量v。 <li><em>step:</em> 当子句执行时,迭代变量 v的更新步骤。 <li><em>pred:</em> 当子句执行时,要测试循环退出的谓词执行。 <li><em>fini:</em> 如果子句导致循环退出,则执行终结器以计算循环的返回值。 </ul> 将按子句顺序记录 (V...)所有迭代变量类型的完整序列。 值本身将是 (v...)。 当我们谈到“参数列表”时,我们通常会引用类型,但在某些上下文(描述执行)中,列表将是实际值。

其中一些子句部分可能会根据某些规则省略,在本例中提供了有用的默认行为。 有关详细说明,请参阅下文。

<em>Parameters 可选,where:/em> Each 子句函数是允许的,<但不需要接受每个迭代变量v的参数。 例外情况是,init 函数不能采用任何 v 参数,因为执行 init 函数时尚未计算这些值。 任何子句函数都可能忽略采用它有权接受的参数的任何尾随子序列。 事实上,任何子句函数都可能没有任何参数。

<em>循环参数:</em> A 子句函数可以采用它有权访问的所有迭代变量值,在这种情况下,它可能还需要更多尾随参数。 此类额外值称为 <em 循环参数</em>,其类型和值被声明为(A...)(a...)>。 这些参数将成为执行循环时要提供的结果循环句柄的参数。 (由于 init 函数不接受迭代变量 v,因此 init 函数的任何参数都是自动循环参数 a。)与迭代变量一样,允许子句函数,但不需要接受循环参数。 这些循环参数充当在整个循环中可见的循环固定值。

<em>Parameters 在任何地方可见:</em> 允许每个非 init 子句函数观察整个循环状态,因为它可以传递当前迭代变量值和传入循环参数的完整列表 (v... a...) 。 init 函数可以以形式 (a...)观察初始预循环状态。 大多数子句函数不需要所有这些信息,但它们将正式连接到它,就像通过它一 #dropArguments样。 >更具体地说,我们将使用表示法(V*)来表达完整序列(V...)的任意前缀(同样,对于(v*)(A*)(a*))。 在该表示法中,init 函数参数列表的一般形式是 (A*),非 init 函数参数列表的一般形式为 (V*)(V... A*)

<em>Checking 子句结构:</em> 给定一组子句,执行许多检查和调整来连接循环的所有部分。 在以下步骤中详细说明了它们。 在这些步骤中,如果循环组合器的输入未满足所需的约束,则“必须”一词的每个匹配项都对应于将引发的位置 IllegalArgumentException

<em>有效相同的序列:</em> “effid”> 参数列表被定义为 <em>有效相同</em> 与另一个参数列表AB(如果A相同)B或如果A较短且与正确的前缀B相同。 在谈到无序参数列表集时,如果集包含最长列表,并且集的所有成员都与该最长列表有效相同,则它们与整个集“有效相同”。 例如,窗体 (V*) 的任何类型序列集实际上相同,如果添加了窗体 (V... A*) 的更多序列,则相同。

<em>步骤 0:确定子句结构。</em><ol type=“a”><li>子句数组(of type MethodHandle[][])必须是非null 且至少包含一个元素。 <li>子句数组可能不包含 null超过四个元素的 s 或子数组。 <li>子句短于四个元素被视为由 null 元素填充为长度为 4 的元素。 填充是通过将元素追加到数组中来进行的。 <将忽略包含所有null项的 li>子句。 <li>Each 子句被视为函数的四元组,称为“init”、“step”、“pred”和“fini”。 </ol>

<em>步骤 1A:确定迭代变量类型 (V...)。</em><ol type=“a”><li>每个子句的迭代变量类型是使用子句的 init 和步骤返回类型确定的。 <li>如果省略这两个函数,则相应的子句没有迭代变量(void 用作指示的类型)。 如果省略其中一个,则另一个的返回类型定义子句的迭代变量类型。 如果同时提供这两种类型,则通用返回类型(它们必须相同)定义子句的迭代变量类型。 <li>表单返回类型列表(按子句顺序),省略所有匹配项 void。 <li>此类型列表称为“迭代变量类型”((V...))。 </ol>

<em>步骤 1B:确定循环参数(A...)。</em><ul><li>检查并收集 init 函数参数列表(格式)。(A*) <li>在删除迭代变量类型后检查并收集步骤、pred 和 fini 参数列表的后缀。 (必须有形式 (V... A*)(A*) 仅收集部件。) <li>Do not collect suffixes from step, pred, and fini parameter lists that not begin with the all iteration variable types. (将在步骤 2 中检查这些类型以及所有子句函数类型。 <li>忽略的子句函数。 (同样,它们被视为具有空参数列表。 <li>所有收集的参数列表必须有效相同。 <li>最长的参数列表(这一定是唯一的)称为“外部参数列表”((A...))。 <li>如果没有此类参数列表,则外部参数列表将设置为空序列。 <li>由迭代变量类型组成的组合列表后跟外部参数类型称为“内部参数列表”。 </ul>

<em>步骤 1C:确定循环返回类型。</em><ol type=“a”><li>Examine fini 函数返回类型,忽略省略的 fini 函数。 <li>如果没有 fini 函数,则循环返回类型为 void。 <li>否则,fini 函数的常见返回类型(其返回类型 R 必须相同)定义循环返回类型。 </ol>

<em>步骤 1D:检查其他类型的。</em><ol type=“a”><li>必须至少有一个未省略的 pred 函数。 <li>每个未省略的 pred 函数都必须具有 boolean 返回类型。 </ol>

<em>步骤 2:确定参数列表。</em><ol type=“a”><li>生成的循环句柄的参数列表将是外部参数列表 (A...)。 <li>init 函数的参数列表将调整为外部参数列表。 (请注意,其参数列表已与此列表有效相同。 <li>每个非省略、非 init(步骤、pred 和 fini)函数的参数列表必须与内部参数列表 (V... A...)有效相同。 </ol>

<em>步骤 3:填写省略的函数。</em><ol type=“a”><li>如果省略 init 函数,请使用子句迭代变量类型的 #empty 默认值。 <li>如果省略步骤函数,请使用子句迭代变量类型的 #identity 标识函数;在上述子句的非void 迭代变量的标识函数参数之前插入已删除的参数参数。 (这将将循环变量转换为局部循环固定。) <li>如果省略了 pred 函数,请使用常量 true 函数。 (就本条款而言,这将保持循环的运行。请注意,在这种情况下,相应的 fini 函数不可访问。 <li>如果省略 fini 函数,请使用循环返回类型的 #empty 默认值。 </ol>

<em>步骤 4:填写缺少的参数类型。</em><ol type=“a”><li>此时,每个 init 函数参数列表实际上都与外部参数列表 (A...)相同,但某些列表可能较短。 对于具有简短参数列表的每个 init 函数,请填充列表的末尾。 <li>此时,每个非 init 函数参数列表实际上都与内部参数列表 (V... A...)相同,但某些列表可能较短。 对于具有简短参数列表的每个非 init 函数,请退出列表的末尾。 <li>参数列表由 #dropArgumentsToMatch(MethodHandle、int、List、int)填充,删除未使用的尾随参数。 </ol>

<em>Final observations.</em><ol type=“a”><li>在这些步骤之后,通过提供省略的函数和参数来调整所有子句。 <li>All init 函数有一个通用的参数类型列表 (A...),最终循环句柄也将具有。 <li>All fini 函数有一个常见的返回类型 R,最终循环句柄也将具有。 <li>所有非 init 函数都有一个常见的参数类型列表 (V... A...)(非void)迭代变量 V ,后跟循环参数。 <li>每对 init 和步骤函数都同意其返回类型 V。 <li>每个非 init 函数都可以观察所有迭代变量的当前值 (v...) 。 <li>Every 函数将能够观察所有循环参数的传入值 (a...) 。 </ol>

<em>示例。</em> 由于上述步骤 1A 的结果, loop 组合器具有以下属性: <ul><li>Given N 子句 Cn = {null, Sn, Pn} 和 n = 1..N。 <li>假设谓词句柄 Pn 要么 null 没有参数。 (只有一个 Pn 必须是非null的。 <li>假设步骤句柄 Sn 具有签名 (B1..BX)Rn,对于某些常量 X>=N。 <li>假设 Q 是非 void 类型的 Rn计数,是 (V1...VQ) 这些类型的序列。 <李>它一定是这样Vn == Bnn = 1..min(X,Q) <li>参数类型 Vn 将解释为循环本地状态元素 (V...)。 <li>任何剩余类型 BQ+1..BX (如果 Q<X) 将确定生成的循环句柄的参数类型 (A...)。 </ul> 在此示例中,循环句柄参数 (A...) 派生自步骤函数,如果大多数循环计算发生在步骤中,则这是自然的。 对于某些循环,计算负担在 pred 函数中可能最为严重,因此 pred 函数可能需要接受循环参数值。 对于具有复杂退出逻辑的循环,fini 函数可能需要接受循环参数,同样,对于具有复杂入口逻辑的循环,init 函数将需要额外的参数。 出于此类原因,确定这些参数的规则在所有子句部件中都尽可能对称。 一般情况下,循环参数作为整个循环中的常见固定值,而迭代变量作为通用变量值运行,或者(如果没有步骤函数)作为内部循环固定临时。

<em>循环执行。</em><ol type=“a”><li>调用循环时,循环输入值保存在局部变量中,传递给每个子句函数。 这些局部变量是循环固定的。 <li>Each init 函数按子句顺序执行(传递外部参数 (a...)),并将非void 值保存(作为迭代变量 (v...))保存到局部变量中。 这些局部变量将循环变化(除非其步骤的行为为标识函数,如上所述)。 <li>所有函数执行(init 函数除外)都将传递内部参数列表,包括非void 迭代值 (v...) (以子句顺序)和循环输入 (a...) (按参数顺序)。 < >然后按子句顺序执行步骤和 pred 函数(pred 之前的步骤),直到 pred 函数返回false。 <li>步骤函数调用的非void 结果用于更新循环变量序列 (v...) 中的相应值。 更新后的值对所有后续函数调用立即可见。 <li>如果 pred 函数返回 false,将调用相应的 fini 函数,并且从整个循环返回生成的值(of type R)。 <li>如果所有 pred 函数始终返回 true,则不会调用任何 fini 函数,并且循环无法退出,除非引发异常。 </ol>

<em>使用情况提示。</em><ul><li>虽然每个步骤函数将接收 em>all</em> 循环变量的<当前值,但有时步骤函数只需要观察其自己的变量的当前值。 在这种情况下,步骤函数可能需要显式 #dropArguments 删除前面的所有循环变量。 这需要在表达式中提及其类型,例如 dropArguments(step, 0, V0.class, ...)。 <li>循环变量不需要改变;它们可以是循环固定变量。 子句可以通过不带步骤、pred 或 fini 函数的合适 init 函数创建循环固定。 这对于将传入循环参数“wire”到相邻循环变量的步骤或 pred 函数中可能很有用。 <li>如果某些子句函数是实例上的虚拟方法,则可以使用初始子句(如 }) new MethodHandle[]{identity(ObjType.class)方便地将实例本身放置在初始固定循环“variable”中。 在这种情况下,实例引用将是第一个迭代变量值,并且可以轻松地将虚拟方法用作子句部分,因为它们都将采用与该值匹配的前导实例引用。 </ul>

下面是生成的循环句柄的伪代码。 如上所述, Vv 表示循环变量的类型和值; Aa 表示传递给整个循环的参数;并且 R 是所有终结器以及生成的循环的常见结果类型。 <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> 注意,参数类型列表 (V...)(A...) 已扩展为其完整长度,即使单个子句函数可能忽略全部。 如上所述,缺少的参数将按如下所示 #dropArgumentsToMatch(MethodHandle, int, List, int)填充。

已在 9 中添加。

Java文档java.lang.invoke.MethodHandles.loop(java.lang.invoke.MethodHandle[]...)

本页的某些部分是根据 创建和共享的工作进行的修改,并根据 许可证中所述的条款使用。

适用于