foreach 3.0
Introdução
Esta é uma nova versão importante do "foreach", vou assumir alguma familiaridade com a versão existente. Se você não tem isso, leia primeiro este tópico: [LINK PERDIDO]
Mudanças recentes
- A maioria dos nomes internos, prefixos e macros foram alterados. Isso não deve ser um problema, pois você não deve usar os internos diretamente ...
- "Iter_InternalArray" agora é "Iter_TrueArray" e "Iter_InternalSize" agora é "Iter_TrueCount". O uso de "Interno" no nome foi confuso, porque eles foram projetados como uma API externa para fornecer acesso direto a alguns detalhes de implementação.
- As funções iteradoras especiais mudaram significativamente. O estilo antigo parecia:
Код:
- Código:
iterfunc Tag:MyIterator(outros, Tag:cur)
{
Marca de
- Código:
retorno:-1;
}
A nova versão se parece com:
Код:
- Código:
#define iterstart@MyIterator -1
iterfunc Tag:MyIterator(cur, other)
{
Marca de
- Código:
retorno:-1;
}
Há duas mudanças principais: A definição "iterstart@" informa ao sistema qual é o valor inválido para o seu iterador - costumava ser -1 por padrão, mas precisava ser mais genérico. O valor "cur" foi movido para o início da lista de parâmetros e perdeu todas as tags opcionais (mesmo que a função ainda retorne uma tag) - isso permite mais de um parâmetro adicional para a função do iterador: "MyIterator(cur , outro, mais, sim)" e "foreach (novo i: MyIterator(3, 4, 5))" - Os valores de retorno de "Iter_Add", "Iter_Remove" e algumas outras funções não são mais booleanos. Em vez disso, eles retornam o valor recém-adicionado/removido do iterador ou -1 em caso de falha.
- Isso agora REQUER YSI - há muitas alterações para manter duas versões paralelas, pois muitos recursos exigiriam o dobro do código sem o YSI.
Observe que essas alterações não devem afetar os usos básicos apenas dos iteradores "Player" e outros.
Novas características
Novas características
- Multi-Iteradores
Um multi-iterador é um iterador em que existem várias listas em um conjunto de elementos e cada elemento pode estar em apenas uma lista. Por exemplo, uma lista de carros próprios. O conjunto de elementos é o conjunto de todos os veículos, cada jogador pode ter uma lista de veículos que possui, e cada veículo pode ter no máximo um proprietário. Anteriormente, isso parecia:
Код:- Código:
novo
Iterator:OwnedVehicles[MAX_PLAYERS]<MAX_VEHICLES>;
Iter_Init(OwnedVehicles);
foreach (new i: OwnedVehicles[playerid])
{
}
Isso funciona, mas é muito ineficiente. Cada jogador tem um espaço para cada veículo, mas como cada veículo só pode pertencer a um jogador, a maioria desses espaços é desperdiçada. Além do mais, não há nada realmente impedindo você de fazer:
Код:- Código:
Iter_Add(OwnedVehicles[5], 5);
Iter_Add(OwnedVehicles[7], 5);
Para atribuir o veículo "5" como propriedade de duas pessoas diferentes.
Um multi-iterador para isso ficaria assim:
Код:Um multi-iterador para isso ficaria assim:
- Código:
novo
Iterator:OwnedVehicles<MAX_PLAYERS, MAX_VEHICLES>;
foreach (novo i: OwnedVehicles<playerid>)
{
}
Existem várias vantagens nisso. Em primeiro lugar, esta matriz é muito menor - em vez de usar (mais de) slots "MAX_PLAYERS * MAX_VEHICLES", ele usa apenas "MAX_PLAYERS + MAX_VEHICLES", que está próximo do ideal. Em segundo lugar, como cada veículo só pode aparecer em um único iterador, este código falhará:
Код:- Código:
Iter_Add(OwnedVehicles<5>, 5);
Iter_Add(OwnedVehicles<7>, 5);
Ao tentar adicionar um veículo, você pode verificar se conseguiu:
Код:- Código:
if (Iter_Add(OwnedVehicles<7>, 5) == -1)
{
// Não é possível adicionar o veículo a este iterador.
}
Você pode verificar se um valor está em uma lista específica:
Код:- Código:
if (Iter_Contains(MyIter<5>, 11))
{
}
Ou está em alguma das listas:
Код:- Código:
if (Iter_Contains(MeuIter<>, 11))
{
}
Remover um valor da lista errada não fará nada, porque não está nessa lista!
Код:- Código:
Iter_Add(MeuIter<5>, 11);
foreach (new i : MyIter<5>) printf("%d", i);
Iter_Remove(MeuIter<7>, 11);
foreach (new i : MyIter<5>) printf("%d", i);
Saídas:
Код:- Código:
11
11
- Iteradores Reversos
A versão antiga do foreach tinha iteradores reversos na forma de "Iter_Prev(iter, x)", mas eles eram desajeitados e lentos. A nova versão fez duas mudanças importantes. Em primeiro lugar, para iteradores NORMAIS (ou seja, não multi-iteradores ou iteradores especiais), retroceder é quase tão rápido quanto avançar). Em segundo lugar, você pode reverter um iterador diretamente:
Код:- Código:
Iter_Add(MeuIter, 4);
Iter_Add(MeuIter, 7);
Iter_Add(MeuIter, 20);
foreach (novo i: Reverse(MyIter))
{
}
Saídas:
Код:- Código:
20
7
4
- Novos iteradores
A versão antiga de "foreach" vinha com quatro iteradores: "Player", "NPC", "Character" e "Bot". Esta nova versão terá mais, atualmente só tem mais uma, e isso é principalmente para uma demonstração especial da função iteradora:
Код:- Código:
foreach (novo i: Faixa(4, 8))
{
printf("%d", i);
}
Saídas:
Код:- Código:
4
5
6
7
Код:
- Código:
foreach (novo i : Range(4, 8, 2))
{
printf("%d", i);
}
Saídas:
Код:- Código:
[size=14][size=13]4
6[/size][/size]
[size=14]Код:
[size=13]foreach (novo i : Range(10, 6, -1))
{
printf("%d", i);
}[/size][/size]
Saídas:
Код:- Código:
10
9
8
7
- Iteradores YSI
Eles não são novos nesta versão, mas não estão realmente documentados. YSI inclui vários iteradores:
Код:- Código:
novo
BitArray:x<100>;
foreach (novo i: Bits(x))
{
// Pega todos os slots que são "1" em "x".
}
Код:
- Código:
novo
BitArray:x<100>;
foreach (novo i: espaços em branco (x))
{
// Pega todos os slots que são "0" em "x".
}
Код:
- Código:
foreach (novo i: Command())
{
// Percorre todos os comandos y_commands.
}
Код:
- Código:
foreach (novo i: PlayerCommand(playerd))
{
// Percorre todos os comandos y_commands que um determinado jogador pode usar.
}
Код:
- Código:
foreach (novo Grupo:i : GroupChild(g))
{
// Percorre todos os grupos filhos de y_groups Group:g.
}
Код:
- Código:
// Deve ser "PlayerGroup", desculpe!
foreach (novo Grupo:i: PlayerGroups(playerid))
{
// Percorre todos os grupos em que um jogador está.
}
Код:
- Código:
foreach (novo i: GroupMemeber(g))
{
// Percorre todos os jogadores de um grupo.
}
Код:
- Código:
foreach (novo Grupo:i: CreatedGroup())
{
// Percorre todos os grupos em y_groups.
}
- depreciação
A sintaxe "foreach (Player, i)", que foi obsoleta ANOS atrás, agora dá um aviso quando usada. O aviso contém o texto "using_deprecated_foreach_syntax". Esta é a única alteração que afetará os usuários regulares, e é por isso que a tornei ininterrupta.
- Erros mais agradáveis
Fazendo isso:
Код:novo
- Código:
Iterator:ArrayIter[10]<20>;
Iter_Add(ArrayIter[5], 10);
Agora dá o seguinte aviso:
Код:O símbolo nunca é usado "Iter_Init@ArrayIter"
A solução, como acontece com todos os iteradores multidimensionais, é chamar "Iter_Init":
Код:novo
- Código:
Iterator:ArrayIter[10]<20>;
Iter_Init(ArrayIter);
Iter_Add(ArrayIter[5], 10);
Infelizmente, o aviso não é infalível. Isso não funcionará, mas compilará silenciosamente:
Код:novo
- Código:
Iterator:ArrayIter[10]<20>;
Iter_Add(ArrayIter[5], 10);
Iter_Init(ArrayIter);
Usar um iterador padrão como um multi-iterador dará o seguinte erro:
Код:- Código:
Símbolo indefinido "Iter_Multi@IterName"
Da mesma forma, usar um iterador múltiplo como um iterador regular dirá:
Код:- Código:
Símbolo indefinido "Iter_Single@IterName"
- Sintaxe de perdão
Com a versão antiga de "foreach", você tinha que fazer este espaçamento:
Код:- Código:
foreach (novo i: jogador)
O seguinte código sutilmente diferente deu erros horríveis:
Код:- Código:
foreach (novo i: Jogador)
Agora não. Na verdade, quase todos os espaçamentos em quaisquer funções agora são aceitos.
- Iter_AllocName
Anteriormente, "Iter_Free" retornaria um valor não presente em um iterador e "Iter_Add" adicionaria um valor. "Iter_Alloc" simplesmente combina os dois recursos - localiza um valor não utilizado, adiciona-o ao iterador e o retorna:
Код:- Código:
novo
val = Iter_Alloc(MeuIter);
- Ortografia correta
Durante anos, houve duas cópias de todas as funções, porque a primeira versão as grafava todas erradas - por exemplo, "Iter_Add" e "Itter_Add". "Iterar" não tem um "t" duplo! As cópias incorretas já foram removidas.
- Limpeza de código
Isso não é realmente uma mudança que afeta o usuário final, mas tudo o que é interno à biblioteca agora é MUITO mais agradável de se trabalhar e ler. Na verdade, ficou ainda melhor durante o desenvolvimento, mas renomeei algumas macros para tornar o código resultante mais curto.
- testes
Eu adicionei isso ao y_testing, para que as alterações possam ser verificadas rapidamente.
Download
Esta versão de "foreach" está na versão mais recente de "YSI" no github:
https://github.com/Misiur/YSI-Includes/tree/YSI.tl
Download
Esta versão de "foreach" está na versão mais recente de "YSI" no github:
https://github.com/Misiur/YSI-Includes/tree/YSI.tl
Creditos: Misiur