MethodHandles.Loop(MethodHandle[][]) Método

Definição

Constrói um identificador de método que representa um loop com várias variáveis de loop que são atualizadas e verificadas em cada iteração.

[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

Parâmetros

clauses
MethodHandle[][]

uma matriz de matrizes (4 tuplas) de MethodHandles adhering às regras descritas acima.

Retornos

um identificador de método que incorpora o comportamento de loop, conforme definido pelos argumentos.

Atributos

Comentários

Constrói um identificador de método que representa um loop com várias variáveis de loop que são atualizadas e verificadas em cada iteração. Após o encerramento do loop devido a um dos predicados, um finalizador correspondente é executado e entrega o resultado do loop, que é o valor retornado do identificador resultante.

Intuitivamente, cada loop é formado por uma ou mais "cláusulas", cada uma especificando uma variável< de iteração local<>/em> e/ou uma saída de loop. Cada iteração do loop executa cada cláusula em ordem. Uma cláusula pode, opcionalmente, atualizar sua variável de iteração; ele também pode, opcionalmente, executar um teste e uma saída de loop condicional. Para expressar essa lógica em termos de identificadores de método, cada cláusula especificará até quatro ações independentes:<ul<>li><>em init:</em> Antes que o loop seja executado, a inicialização de uma variável v de iteração do tipoV. <li><em>step:</em> Quando uma cláusula é executada, uma etapa de atualização para a variável vde iteração. <li><em>pred:</em> Quando uma cláusula é executada, uma execução de predicado para testar a saída do loop. <li><em>fini:</em> Se uma cláusula causar uma saída de loop, uma execução do finalizador calculará o valor retornado do loop. </ul> A sequência completa de todos os tipos de variáveis de iteração, na ordem da cláusula, será notada como (V...). Os próprios valores serão (v...). Quando falamos em "listas de parâmetros", geralmente nos referiremos aos tipos, mas em alguns contextos (descrevendo a execução), as listas serão de valores reais.

Algumas dessas partes de cláusula podem ser omitidas de acordo com determinadas regras e o comportamento padrão útil é fornecido nesse caso. Veja abaixo uma descrição detalhada.

<em>Parâmetros opcionais em todos os lugares:</em> Cada função de cláusula é permitida, mas não é necessária para aceitar um parâmetro para cada variável vde iteração. Como exceção, as funções de inicialização não podem usar parâmetros v , pois esses valores ainda não são computados quando as funções de inicialização são executadas. Qualquer função de cláusula pode deixar de usar qualquer subsequência à direita dos parâmetros que tem o direito de usar. Na verdade, qualquer função de cláusula pode não ter argumentos.

<em>Parâmetros loop:</em> Uma função de cláusula pode levar todos os valores de variável de iteração a que tem direito, nesse caso, ele também pode ter mais parâmetros à direita. Esses valores extras são chamados <em>parâmetros< de loop/em>, com seus tipos e valores notados como (A...) e (a...). Eles se tornam os parâmetros do identificador de loop resultante, a serem fornecidos sempre que o loop for executado. (Como as funções de inicialização não aceitam variáveis vde iteração, qualquer parâmetro para uma função de inicialização é automaticamente um parâmetro ade loop .) Assim como acontece com variáveis de iteração, as funções de cláusula são permitidas, mas não são necessárias para aceitar parâmetros de loop. Esses parâmetros de loop atuam como valores invariáveis de loop visíveis em todo o loop.

<em>Parâmetros visíveis em todos os lugares:</em> Cada função de cláusula não init tem permissão para observar todo o estado do loop, pois pode ser passada a lista (v... a...) completa de valores de variáveis de iteração atuais e parâmetros de loop de entrada. As funções de inicialização podem observar o estado inicial do pré-loop, no formulário (a...). A maioria das funções de cláusula não precisará de todas essas informações, mas elas serão formalmente conectadas a ela como se fossem.#dropArguments "astar"> Mais especificamente, usaremos a notação (V*) para expressar um prefixo arbitrário de uma sequência (V...) completa (e da mesma forma para (v*), (A*), ). (a*) Nessa notação, a forma geral de uma lista de parâmetros de função init é (A*), e a forma geral de uma lista de parâmetros de função não init é (V*) ou (V... A*).

<em>Estrutura de cláusula de verificação:</em> Dado um conjunto de cláusulas, há uma série de verificações e ajustes executados para conectar todas as partes do loop. Eles são escritos em detalhes nas etapas abaixo. Nestas etapas, cada ocorrência da palavra "deve" corresponde a um local em que IllegalArgumentException será gerada se a restrição necessária não for atendida pelas entradas para o combinador de loop.

<em>Sequências efetivamente idênticas:</em> "effid"> Uma lista A de parâmetros é definida para ser <>efetivamente idêntica</em> outra lista B de parâmetros se A e B forem idênticas, ou se A for mais curta e for idêntica a um prefixo adequado de B. Ao falar de um conjunto não ordenado de listas de parâmetros, dizemos que o conjunto é "efetivamente idêntico" como um todo se o conjunto contiver uma lista mais longa e todos os membros do conjunto forem efetivamente idênticos a essa lista mais longa. Por exemplo, qualquer conjunto de sequências de tipo do formulário (V*) é efetivamente idêntico e o mesmo será verdadeiro se mais sequências do formulário (V... A*) forem adicionadas.

<em>Etapa 0: determinar a estrutura da cláusula.</em><ol type="a"><li>A matriz de cláusula (do tipo MethodHandle[][]) deve ser diferentenull e conter pelo menos um elemento. <li>A matriz de cláusulas pode não conter nulls ou subconjuntos com mais de quatro elementos. <As cláusulas li>com menos de quatro elementos são tratadas como se fossem adicionadas por null elementos ao comprimento quatro. O preenchimento ocorre acrescentando elementos à matriz. <As cláusulas li>com todos os nulls são desconsideradas. <li>Cada cláusula é tratada como uma tupla de quatro funções, chamadas "init", "step", "pred" e "fini". </ol>

<em>Etapa 1A: Determinar tipos (V...)de variável de iteração.</em><ol type="a"><li>O tipo de variável de iteração para cada cláusula é determinado usando os tipos de entrada e retorno de etapa da cláusula. <li>Se ambas as funções forem omitidas, não haverá nenhuma variável de iteração para a cláusula correspondente (void é usada como o tipo para indicar isso). Se um deles for omitido, o tipo de retorno do outro definirá o tipo de variável de iteração da cláusula. Se ambos forem fornecidos, o tipo de retorno comum (eles devem ser idênticos) define o tipo de variável de iteração da cláusula. <li>Forme a lista de tipos de retorno (em ordem de cláusula), omitindo todas as ocorrências de void. <li>Esta lista de tipos é chamada de "tipos de variável de iteração" ((V...)). </ol>

<em>Etapa 1B: Determinar parâmetros (A...)de loop.</em><ul><li>Examinar e coletar listas de parâmetros de função de emissão (que são do formulário (A*)). <li>Examinar e coletar os sufixos das listas de parâmetros step, pred e fini, depois de remover os tipos de variável de iteração. (Eles devem ter o formulário (V... A*); coletar somente as (A*) partes.) <li>Não coletar sufixos de listas de parâmetros de etapa, pred e fini que não começam com todos os tipos de variável de iteração. (Esses tipos serão verificados na etapa 2, juntamente com todos os tipos de função de cláusula.) <li>As funções de cláusula omitida são ignoradas. (Equivalentemente, eles são considerados com listas de parâmetros vazias.) <li>Todas as listas de parâmetros coletadas devem ser efetivamente idênticas. <li>A lista de parâmetros mais longa (que é necessariamente exclusiva) é chamada de "lista de parâmetros externos" ((A...)). <li>Se não houver essa lista de parâmetros, a lista de parâmetros externos será usada para ser a sequência vazia. <li>A lista combinada que consiste em tipos de variáveis de iteração seguidos pelos tipos de parâmetro externo é chamada de "lista de parâmetros internos". </ul>

<em>Etapa 1C: Determinar o tipo de retorno de loop.</em><ol type="a"><li>Examine tipos de retorno de função fini, desconsiderando funções fini omitidas. <li>Se não houver funções fini, o tipo de retorno de loop será void. <li>Caso contrário, o tipo R de retorno comum das funções fini (seus tipos de retorno devem ser idênticos) define o tipo de retorno de loop. </ol>

<em>Etapa 1D: Verificar outros tipos.</em><ol type="a"><li>Deve haver pelo menos uma função de pred não omitida. <li>Cada função de pred não omitida deve ter um boolean tipo de retorno. </ol>

<em>Etapa 2: Determinar listas de parâmetros.</em><ol type="a"><li>A lista de parâmetros para o identificador de loop resultante será a lista (A...)de parâmetros externos. <li>A lista de parâmetros para funções de inicialização será ajustada à lista de parâmetros externos. (Observe que suas listas de parâmetros já são efetivamente idênticas a esta lista.) <li>A lista de parâmetros para cada função não omitida, não init (step, pred e fini) deve ser efetivamente idêntica à lista (V... A...)de parâmetros interna. </ol>

<em>Etapa 3: preencher funções omitidas.</em><ol type="a"><li>Se uma função de init for omitida, use um valor padrão #empty para o tipo de variável de iteração da cláusula. <li>Se uma função de etapa for omitida, use uma função de identidade #identity do tipo de variável de iteração da cláusula; insira parâmetros de argumento descartados antes do parâmetro de função de identidade para as variáveis de nãovoid iteração das cláusulas anteriores. (Isso transformará a variável de loop em um loop local invariável.) <li>Se uma função predefinida for omitida, use uma função constante true . (Isso manterá o loop em andamento, no que diz respeito a esta cláusula. Observe que, nesses casos, a função fini correspondente é inacessível.) <li>Se uma função fini for omitida, use um valor padrão #empty para o tipo de retorno de loop. </ol>

<em>Etapa 4: preencha os tipos de parâmetro ausentes.</em><ol type="a"><li>Neste ponto, cada lista de parâmetros de função de init é efetivamente idêntica à lista (A...)de parâmetros externos, mas algumas listas podem ser mais curtas. Para cada função de inicialização com uma lista de parâmetros curta, remova o final da lista. <li>Neste ponto, cada lista de parâmetros de função não init é efetivamente idêntica à lista (V... A...)de parâmetros internos, mas algumas listas podem ser mais curtas. Para cada função não inicial com uma lista de parâmetros curta, remova o final da lista. <as listas de argumentos li>são adicionadas por #dropArgumentsToMatch(MethodHandle, int, List, int) descartando argumentos à direita não utilizados. </ol>

<em>Observações finais.</em><ol type="a"><li>Após essas etapas, todas as cláusulas foram ajustadas fornecendo funções e argumentos omitidos. <li>Todas as funções de inicialização têm uma lista (A...)de tipos de parâmetro comum, que o identificador de loop final também terá. <li>Todas as funções fini têm um tipo Rde retorno comum, que o identificador de loop final também terá. <li>Todas as funções não init têm uma lista (V... A...)de tipos de parâmetro comum, de variáveis de iteração (não)void seguidas V por parâmetros de loop. <li>Cada par de funções de inicialização e etapa concorda em seu tipo Vde retorno. <li>Cada função não inicial será capaz de observar os valores (v...) atuais de todas as variáveis de iteração. <li>Cada função será capaz de observar os valores (a...) de entrada de todos os parâmetros de loop. </ol>

<em>Exemplo.</em> Como consequência da etapa 1A acima, o loop combinador tem a seguinte propriedade: <cláusulas Cn = {null, Sn, Pnul><li>Given N } com n = 1..N. <li>Suponha que as alças Pn de predicado sejam null ou não tenham parâmetros. (Apenas um Pn tem que ser nãonull.) <li>Suponha que os identificadores Sn de etapa tenham assinaturas (B1..BX)Rn, para alguma constante X>=N. <li>Suppose Q é a contagem de tipos Rnnão nulos e (V1...VQ) é a sequência desses tipos. <li>Deve ser isso Vn == Bn para n = 1..min(X,Q). <li>Os tipos Vn de parâmetro serão interpretados como elementos (V...)de estado local de loop. <li>Todos os tipos restantes BQ+1..BX (se Q<X) determinarão os tipos (A...)de parâmetro do identificador de loop resultante. </ul> Neste exemplo, os parâmetros de alça de loop foram derivados (A...) das funções de etapa, o que é natural se a maior parte da computação de loop ocorrer nas etapas. Para alguns loops, a carga da computação pode ser mais pesada nas funções anteriores e, portanto, as funções predefinidas podem precisar aceitar os valores de parâmetro de loop. Para loops com lógica de saída complexa, as funções fini podem precisar aceitar parâmetros de loop e, da mesma forma, para loops com lógica de entrada complexa, em que as funções de inicialização precisarão dos parâmetros extras. Por esses motivos, as regras para determinar esses parâmetros são o mais simétricas possível, em todas as partes da cláusula. Em geral, os parâmetros de loop funcionam como valores invariáveis comuns em todo o loop, enquanto as variáveis de iteração funcionam como valores variantes comuns ou (se não houver nenhuma função de etapa) como temporariamente invariáveis de loop interno.

<em Execução de>loop.</em><ol type="a"><li>Quando o loop é chamado, os valores de entrada de loop são salvos em locais, para serem passados para cada função de cláusula. Esses locais são invariáveis de loop. <li>Cada função de inicialização é executada na ordem da cláusula (passando os argumentos externos (a...)) e os valores não-valoresvoid são salvos (como variáveis (v...)de iteração) em locais. Esses locais terão um loop variável (a menos que suas etapas se comportem como funções de identidade, conforme observado acima). <li>Todas as execuções de função (exceto as funções de inicialização) serão passadas na lista de parâmetros internos, consistindo nos valores (v...) de nãovoid iteração (na ordem da cláusula) e, em seguida, as entradas (a...) de loop (em ordem de argumento). <li>As funções de etapa e pred são executadas, em ordem de cláusula (etapa antes da predefinição), até que uma função anterior retorne false. <li>O resultado não resultantevoid de uma chamada de função de etapa é usado para atualizar o valor correspondente na sequência (v...) de variáveis de loop. O valor atualizado é imediatamente visível para todas as chamadas de função subsequentes. <li>Se uma função predefini retornar false, a função fini correspondente é chamada e o valor resultante (do tipo R) é retornado do loop como um todo. <li>Se todas as funções predefinidas sempre retornarem true, nenhuma função fini será invocada e o loop não poderá sair, exceto lançando uma exceção. </ol>

<em>Dicas de uso.</em><ul><li>Embora cada função de etapa receba os valores atuais de <todas>/em> variáveis< de loop, às vezes uma função de etapa só precisa observar o valor atual de sua própria variável. Nesse caso, a função de etapa pode precisar #dropArguments descartar explicitamente todas as variáveis de loop anteriores. Isso exigirá a menção de seus tipos, em uma expressão como dropArguments(step, 0, V0.class, ...). <As variáveis li>Loop não são necessárias para variar; elas podem ser invariáveis de loop. Uma cláusula pode criar um loop invariável por uma função de inicialização adequada sem nenhuma etapa, pred ou função fini. Isso pode ser útil para "conectar" um argumento de loop de entrada na etapa ou função anterior de uma variável de loop adjacente. <li>Se algumas das funções de cláusula forem métodos virtuais em uma instância, a instância em si poderá ser convenientemente colocada em um loop invariável inicial "variável", usando uma cláusula inicial como new MethodHandle[]{identity(ObjType.class)}. Nesse caso, a referência de instância será o primeiro valor de variável de iteração e será fácil usar métodos virtuais como partes de cláusula, pois todos eles terão uma referência de instância principal que corresponda a esse valor. </ul>

Aqui está o pseudocódigo para o identificador de loop resultante. Como acima, V e v represente os tipos e valores de variáveis de loop; A e a represente argumentos passados para o loop inteiro; e R é o tipo de resultado comum de todos os finalizadores, bem como do loop resultante. <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> Observe que o tipo de parâmetro lista (V...) e (A...) foi expandido para seu comprimento total, embora as funções de cláusula individuais possam não levar todos eles. Conforme observado acima, os parâmetros ausentes são preenchidos como se por #dropArgumentsToMatch(MethodHandle, int, List, int).

Adicionado em 9.

Documentação Java para java.lang.invoke.MethodHandles.loop(java.lang.invoke.MethodHandle[]...).

Partes desta página são modificações baseadas no trabalho criado e compartilhado pelo Android Open Source Project e usadas de acordo com os termos descritos na Licença de Atribuição Creative Commons 2.5.

Aplica-se a