|
Nel capitolo precedente ci siamo soffermati ad analizzare una particolare categoria di tipi di dato, gli enumeratori, strumenti capaci
di rappresentare tramite costanti numeriche possibilità, scelte, opzioni, flags e in genere valori che si possano scegliere in un
insieme finito di elementi. Le strutture, invece, appartengono ad un'altra categoria. Anch'esse rappresentano un tipo di dato derivato,
o complesso, poiché non rientra fra i tipi base (di cui ho già parlato) ma è da essi composto. Le strutture ci permettono
di creare nuovi tipi di dato che possano adattarsi in modo migliore alla logica dell'applicazione che si sta scrivendo: in realtà, quello
che permettono di fare è una specie di "collage" di variabili. Ad esempio, ammettiamo di voler scrivere una rubrica, in grado di
memorizzare nome, cognome e numero di telefono dei nostri principali amici e conoscenti. Ovviamente, dato che si tratta di tante persone,
avremo bisogno di array per contenere tutti i dati, ma in che modo li potremmo immagazzinare? Per quello che ho illustrato fino a questo punto,
la soluzione più lampante sarebbe quella di dichiarare tre array, uno per i nomi, uno per i cognomi e uno per i numeri telefonici.
Dim Names() As String
Dim Surnames() As String
Dim PhoneNumbers() As String
Inutile dire che seguendo questo approccio il codice risulterebbe molto confusionario e poco aggiornabile: se si volesse aggiungere, ad esempio,
un altro dato, "data di nascita", si dovrebbe dichiarare un altro array e modificare pressoch? tutte le parti del listato. Usando una struttura,
invece, potremmo creare un nuovo tipo di dato che contenga al suo interno tutti i campi necessari:
Structure Contact
Dim Name, Surname, PhoneNumber As String
End Structure
'...
'Un array di conttati, ognuno rappresentato dalla struttura Contact
Dim Contacts() As Contact
Come si vede dall'esempio, la sintassi usata per dichiarare una struttura è la seguente:
Structure [Nome]
Dim [Campo1] As [Tipo]
Dim [Campo2] As [Tipo]
'...
End Structure
Una volta dichiarata la struttura e una variabile di quel tipo, però, come si fa ad accedere ai campi in essa presenti? Si usa l'operatore
punto ".", posto dopo il nome della variabile:
Module Module1
Structure Contact
Dim Name, Surname, PhoneNumber As String
End Structure
Sub Main()
Dim A As Contact
A.Name = "Mario"
A.Surname = "Rossi"
A.PhoneNumber = "333 33 33 333"
End Sub
End Module
[Ricordate che le dichiarazioni di nuovi tipi di dato (fino ad ora quelli che abbiamo analizzato sono enumeratori e strutture, e le classi solo
come introduzione) possono essere fatte solo a livello di classe o di namespace, e mai dentro ad un metodo.]
Una struttura, volendo ben vedere, non è altro che un agglomerato di più variabili di tipo base e, cosa molto importante, è
un tipo value, quindi si comporta esattamente come Integer, Short, Date, eccetera... e viene memorizzata direttamente sullo stack, senza uso
di puntatori.
Acrobazie con le strutture
Ma ora veniamo al codice vero e proprio. Vogliamo scrivere quella rubrica di cui avevo parlato prima, ecco un inizio:
Module Module1
Structure Contact
Dim Name, Surname, PhoneNumber As String
End Structure
Sub Main()
'Contacts(-1) inizializza un array vuoto,
'ossia con 0 elementi
Dim Contacts(-1) As Contact
Dim Command As Char
Do
Console.Clear()
Console.WriteLine("Rubrica -----")
Console.WriteLine("Selezionare l'azione desiderata:")
Console.WriteLine("N - Nuovo contatto;")
Console.WriteLine("T - Trova contatto;")
Console.WriteLine("E - Esci.")
Command = Char.ToUpper(Console.ReadKey().KeyChar)
Console.Clear()
Select Case Command
Case "N"
'Usa ReDim Preserve per aumentare le dimensioni
'dell'array mentenendo i dati già presenti.
'L'uso di array e di redim, in questo caso, è
'sconsigliato, a favore delle più versatili
'Liste, che però non ho ancora introdotto.
'Ricordate che il valore specificato tra
'parentesi indica l'indice massimo e non
'il numero di elementi.
'Se, all'inizio, Contacts.Length è 0,
'richiamando ReDim Contacts(0), si aumenta
'la lunghezza dell'array a uno, poiché
'in questo caso l'indice massimo è 0,
'ossia quello che indica il primo e
'l'unico elemento
ReDim Preserve Contacts(Contacts.Length)
Dim N As Contact
Console.Write("Nome: ")
N.Name = Console.ReadLine
Console.Write("Cognome: ")
N.Surname = Console.ReadLine
Console.Write("Numero di telefono: ")
N.PhoneNumber = Console.ReadLine
'Inserisce nell'ultima cella dell'array
'l'elemento appena creato
Contacts(Contacts.Length - 1) = N
Case "T"
Dim Part As String
Console.WriteLine("Inserire nome o cognome del " & _
"contatto da trovare:")
Part = Console.ReadLine
For Each C As Contact In Contacts
'Il confronto avviene in modalità
'case-insensitive: sia il nome/cognome
'che la stringa immessa vengono
'ridotti a Lower Case, così da
'ignorare la differenza tra
'minuscole e maiuscole, qualora presente
If (C.Name.ToLower() = Part.ToLower()) Or _
(C.Surname.ToLower() = Part.ToLower()) Then
Console.WriteLine("Nome: " & C.Name)
Console.WriteLine("Cognome: " & C.Surname)
Console.WriteLine("Numero di telefono: " & C.PhoneNumber)
Console.WriteLine()
End If
Next
Case "E"
Exit Do
Case Else
Console.WriteLine("Comando sconosciuto!")
End Select
Console.ReadKey()
Loop
End Sub
End Module
Ora ammettiamo di voler modificare il codice per permettere l'inserimento di più numeri di telefono:
Module Module1
Structure Contact
Dim Name, Surname As String
'Importante: NON è possibile specificare le dimensioni
'di un array dentro la dichiarazione di una struttura.
'Risulta chiaro il motivo se ci si pensa un attimo.
'Noi stiamo dichiarando quali sono i campi della struttura
'e quale è il loro tipo. Quindi specifichiamo che
'PhoneNumbers è un array di stringhe, punto. Se scrivessimo
'esplicitamente le sue dimensioni lo staremmo creando
'fisicamente nella memoria, ma questa è una
'dichiarazione, come detto prima, e non una
'inizializzazione. Vedremo in seguito che questa
'differenza è molto importante per i tipi reference
'(ricordate, infatti, che gli array sono tipi reference).
Dim PhoneNumbers() As String
End Structure
Sub Main()
Dim Contacts(-1) As Contact
Dim Command As Char
Do
Console.Clear()
Console.WriteLine("Rubrica -----")
Console.WriteLine("Selezionare l'azione desiderata:")
Console.WriteLine("N - Nuovo contatto;")
Console.WriteLine("T - Trova contatto;")
Console.WriteLine("E - Esci.")
Command = Char.ToUpper(Console.ReadKey().KeyChar)
Console.Clear()
Select Case Command
Case "N"
ReDim Preserve Contacts(Contacts.Length)
Dim N As Contact
Console.Write("Nome: ")
N.Name = Console.ReadLine
Console.Write("Cognome: ")
N.Surname = Console.ReadLine
'Ricordate che le dimensioni dell'array non
'sono ancora state impostate:
ReDim N.PhoneNumbers(-1)
'Continua a chiedere numeri di telefono finché
'non si introduce più nulla
Do
ReDim Preserve N.PhoneNumbers(N.PhoneNumbers.Length)
Console.Write("Numero di telefono " & N.PhoneNumbers.Length & ": ")
N.PhoneNumbers(N.PhoneNumbers.Length - 1) = Console.ReadLine
Loop Until N.PhoneNumbers(N.PhoneNumbers.Length - 1) = ""
'Ora l'ultimo elemento dell'array è sicuramente
'vuoto, lo si dovrebbe togliere.
Contacts(Contacts.Length - 1) = N
Case "T"
Dim Part As String
Console.WriteLine("Inserire nome o cognome del " & _
"contatto da trovare:")
Part = Console.ReadLine
For Each C As Contact In Contacts
If (C.Name.ToLower() = Part.ToLower()) Or _
(C.Surname.ToLower() = Part.ToLower()) Then
Console.WriteLine("Nome: " & C.Name)
Console.WriteLine("Cognome: " & C.Surname)
Console.WriteLine("Numeri di telefono: ")
For Each N As String In C.PhoneNumbers
Console.WriteLine(" - " & N)
Next
Console.WriteLine()
End If
Next
Case "E"
Exit Do
Case Else
Console.WriteLine("Comando sconosciuto!")
End Select
Console.ReadKey()
Loop
End Sub
End Module
In questi esempi ho cercato di proporre i casi più comuni di struttura, almeno per quanto si è visto fino ad adesso: una struttura
formata da campi di tipo base e una composta dagli stessi campi, con l'aggiunta di un tipo a sua volta derivato, l'array. Fino ad ora, infatti,
ho sempre detto che la struttura permette di raggruppare più membri di tipo base, ma sarebbe riduttivo restringere il suo ambito di
competenza solo a questo. In realtà può contenere variabili di qualsiasi tipo, comprese altre strutture. Ad esempio,
un contatto avrebbe potuto anche contenere l'indirizzo di residenza, il quale avrebbe potuto essere stato rappresentato a sua volta da
un'ulteriore struttura:
Structure Address
Dim State, Town As String
Dim Street, CivicNumber As String
Dim Cap As String
End Structure
Structure Contact
Dim Name, Surname As String
Dim PhoneNumbers() As String
Dim Home As Address
End Structure
Per accedere ai campi di Home si sarebbe utilizzato un ulteriore punto:
Dim A As Contact
A.Name = "Mario"
A.Surname = "Rossi"
ReDim A.PhoneNumbers(0)
A.PhoneNumbers(0) = "124 90 87 111"
A.Home.State = "Italy"
A.Home.Town = "Pavia"
A.Home.Street = "Corso Napoleone"
A.Home.CivicNumber = "96/B"
A.Home.Cap = "27010"
|
|