Iterazioni (foreach/for)

Una breve introduzione sulle iterazioni. Occorre sempre ricordare l'estrema flessibilità delle tabelle LUA e dei problemi che, conseguentemente, possono sorgere.

Utilizzare il costrutto foreach su una LuaTable è possibile. Occorre ricordare però due punti:

  • L'iteratore scorre la tabella come una lista, quindi da i=1 a i= getn(). Gli elementi memorizzati con chiave-valore non vengono iterati
  • Occorre essere certi dei tipi che si stanno iterando. Nel dubbio usare object e castare a mano.

Il primo punto è abbastanza chiaro. Sul secondo occorre essere molto precisi. Occorre ricordare che in lua si può inserire di tutto in una tabella (interi, stringhe oggetti, nil), quindi occorre valutare in .NET come gestire questi casi.

Anche se i tipi sono uniformi (per esempio stringhe) occorre considerare il caso in cui un indice abbia un valore nil. Questo viene ritornato come oggetto nullo.

Un altro caso da tenere in considerazione è il campo nascosto 'n' che il lua usa come contatore degli elementi nella parte lista della table. Il lua ne fa un uso molto libero: le tabelle sono consistenti anche se il campo non esiste. Questo campo viene creato automaticamente secondo necessità (per esempio tinsert).

vbluanet gestisce questo campo: gli iteratori non ne tengono conto. Solo nel caso dell'iteratore sui campi Values or Keys questo valore veniva ritornato. Dalla versione 17 (in corso) è stato modificato il comportamento della hashtable interna per scartare questa chiave e renderla in questo modo trasparente.

Esempio LuaTable() [C#]

-- tabella lua da iterare
-- Notare: [4] è un intero e non una stringa
-- Notare: [3] è nil
{
  [1]='C01005D',
  [2]='Dosatore tradizionale\nSingola via',
  [4]=180,
}
// iterazione potenzialmente ERRATA
foreach (string s in row)
{
  if (!String.IsNullOrEmpty(s))
    Console.WriteLine("{0}", s.ToString());
  else
    Console.WriteLine("null");
  }
}
// iterazione CORRETTA
foreach (object s in row)
{
  if (s != null)
    Console.WriteLine("{0}", s.ToString());
  else
    Console.WriteLine("null");
  }
}
// iterazione CORRETTA ma pericolosa
int n = row.GetN();
for (int j = 1; j <= n; j++)
{
  string s = row[j] as string;   // <-- C# casta da intero a stringa
  if (!String.IsNullOrEmpty(s))
    Console.WriteLine("[R{0}/C{1}] = {2}", i, j, s);
  else
    Console.WriteLine("[R{0}/C{1}] = null", i, j);
}