Oppure

Loading

Il costrutto iterativo For Each

Questo costrutto iterativo è simile al normale For, ma, invece di avere una variabile contatore numerica, ha una variabile contatore di vario tipo. In sostanza, questo ciclo itera attraverso una array o una collezione di altro genere, selezionando, di volta in volta, l'elemento che si trova alla posizione corrente nell'array. Il suo funzionamento intrinseco è troppo complesso da spiegare ora, quindi lo affronterò solamente nei capitoli dedicati alle interfacce, in particolare parlando dell'interfaccia IEnumerable. La sintassi è la seguente:
Dim A As [tipo]
For Each A In [array/collezione]
    'istruzioni
Next 
Ovviamente anche in questo caso, come nel normale For, è possibile inizializzare una variabile contatore all'interno del costrutto:
For Each A As [tipo] in [array/collezione] ... 
Esempio:
Module Module1
    Sub Main()
        Dim Words() As String = {"Questo", "è", "un", "array", "di", "stringhe"}

        For Each Str As String In Words
            Console.Write(Str & " ")
        Next
        
        'A schermo apparirà la frase:
        ' "Questo è un array di stringhe "

        Console.ReadKey()
    End Sub
End Module 
Per avere un termine di paragone, il semplicissimo codice proposto equivale, usando un for normale, a questo:
'Words.Length restituisce il numero di elementi
'presenti nell'array Words
For I As Int32 = 0 To Words.Length - 1
    Console.Write(Words(I) & " ")
Next 


Gli array sono un tipo reference

Diversamente da come accade in altri linguaggi, gli array sono un tipo reference, indipendentemente dal tipo di dati da essi contenuto. Ciò significa che si comportano come ho spiegato nel capitolo "Tipi reference e tipi value": l'area di memoria ad essi associata non contiene il loro valore, ma un puntatore alla loro posizione nell'heap managed. Questo significa che l'operatore = tra due array non copia il contenuto di uno nell'altro, ma li rende identici, ossia lo stesso oggetto. Per lo stesso motivo, è anche lecito distruggere logicamente un array ponendolo uguale a Nothing: questa operazione può salvare un discreto ammontare di memoria, ad esempio quando si usano grandi array per la lettura di file binari, ed è sempre bene annullare un array dopo averlo usato.
Module Module1
    Sub Main()
        'A e B sono due array di interi
        Dim A() As Int32 = {1, 2, 3}
        Dim B() As Int32 = {4, 5, 6}

        'Ora A e B sono due oggetti diversi e contengono
        'numeri diversi. Questa riga stamperà sullo
        'schermo "False", infatti A Is B = False
        Console.WriteLine(A Is B)
        'Adesso poniamo A uguale a B. Dato che gli array
        'sono un tipo reference, da ora in poi, entrambi
        'saranno lo stesso oggetto
        A = B
        'Infatti questa istruzione stamperà a schermo
        ''"True", poiché A Is B = True
        Console.WriteLine(A Is B)
        'Dato che A e B sono lo stesso oggetto, se modifichiamo
        'un valore dell'array riferendoci ad esso con il nome
        'B, anche richiamandolo con A, esso mostrerà
        'che l'ultimo elemento è lo stesso
        B(2) = 90
        'Su schermo apparirà 90
        Console.WriteLine(A(2))

        Dim C() As Int32 = {7, 8, 9}
        B = C
        'Ora cosa succede?

        Console.ReadKey()
    End Sub
End Module 
Ecco come appare la memoria dopo l'assegnazione A = B:


Ed ecco come appare dopo l'assegnazione B = C:


Come si vede, le variabili contengono solo l'indirizzo degli oggetti effettivi, perciò ogni singola variabile (A, B o C) può puntare allo stesso oggetto ma anche a oggetti diversi: se A = B e B = C, non è vero che A = C, come si vede dal grafico. L'indirizzo di memoria contenuto in A non cambia se non si usa esplicitamente un operatore di assegnamento.
Se state leggendo la guida un capitolo alla volta, potete fermarvi qui: il prossimo paragrafo è utile solo per consultazione.


Manipolazione di array

La classe System.Array contiene molti metodi statici utili per la manipolazione degli array. I più usati sono:
  • Clear(A, I, L) : cancella L elementi a partire dalla posizione I nell'array A
  • Clone() : crea una coppia esatta dell'array
  • ConstrainedCopy(A1, I1, A2, I2, L) : copia L elementi dall'array A1 a partire dall'indice I1 nell'array A2, a partire dall'indice I2; se la copia non ha successo, ogni cambiamento sarà annullato e l'array di destinazione non subirà alcun danno
  • Copy(A1, A2, L) / CopyTo(A1, A2) : il primo metodo copia L elementi da A1 a A2 a partire dal primo, mentre il secondo fa una copia totale dell'array A1 e la deposita in A2
  • Find / FindLast (A, P(Of T)) As T : cerca il primo elemento dell'array A per il quale la funzione generic Of T assegnata al delegate P restituisce un valore True, e ne ritorna il valore
  • Find(A, P(Of T)) As T() : cerca tutti gli elementi dell'array A per i quali la funzione generic Of T assegnata al delegate P restituisce un valore True
  • FindIndex / FindLastIndex (A, P(Of T)) As Int32 : cerca il primo o l'ultimo elemento dell'array A per il quale la funzione generic Of T assegnata al delegate P restituisce un valore True, e ne ritorna l'indice
  • ForEach(A(Of T)) : esegue un'azione A determinata da un delegate Sub per ogni elemento dell'array
  • GetLength(A) : restituisce la dimensione dell'array
  • IndexOf(A, T) / LastIndexOf(A, T) : restituisce il primo o l'ultimo indice dell'oggetto T nell'array A
  • Reverse(A) : inverte l'ordine di tutti gli elementi nell'array A
  • Sort(A) : ordina alfabeticamente l'array A. Esistono 16 versioni di questa procedura, tra le quali una accetta come secondo parametro un oggetto che implementa un'interfaccia IComparer che permette di decidere come ordinare l'array
Molti di questi metodi, come si è visto, comprendono argomenti molto avanzati: quando sarete in grado di comprendere i Generics e i Delegate, ritornate a fare un salto in questo capitolo: scoprirete la potenza di questi metodi.





A cura di: Il Totem