VBA
Dichiarazione delle variabili
Ricerca…
Dichiarazione implicita ed esplicita
Se un modulo di codice non contiene Option Explicit
nella parte superiore del modulo, allora il compilatore automaticamente (cioè, "implicitamente") creerà delle variabili per te quando le utilizzerai. Verrà impostato di default su Variant
tipo variabile.
Public Sub ExampleDeclaration()
someVariable = 10 '
someOtherVariable = "Hello World"
'Both of these variables are of the Variant type.
End Sub
Nel codice precedente, se viene specificata l' Option Explicit
, il codice verrà interrotto perché mancano le istruzioni Dim
necessarie per someVariable
e someOtherVariable
someVariable
someOtherVariable
.
Option Explicit
Public Sub ExampleDeclaration()
Dim someVariable As Long
someVariable = 10
Dim someOtherVariable As String
someOtherVariable = "Hello World"
End Sub
È consigliabile utilizzare l'opzione Explicit nei moduli di codice per assicurarsi di dichiarare tutte le variabili.
Consulta le best practice di VBA su come impostare questa opzione per impostazione predefinita.
variabili
Scopo
Una variabile può essere dichiarata (in aumento del livello di visibilità):
- A livello di procedura, utilizzando la parola chiave
Dim
in qualsiasi procedura; una variabile locale . - A livello di modulo, utilizzando la parola chiave
Private
in qualsiasi tipo di modulo; un campo privato . - A livello di istanza, utilizzando la parola chiave
Friend
in qualsiasi tipo di modulo di classe; un campo amico - A livello di istanza, utilizzando la parola chiave
Public
in qualsiasi tipo di modulo di classe; un campo pubblico . - Globalmente, usando la parola chiave
Public
in un modulo standard ; una variabile globale .
Le variabili dovrebbero sempre essere dichiarate con il più piccolo ambito possibile: preferire il passaggio dei parametri alle procedure, piuttosto che la dichiarazione delle variabili globali.
Vedi Modificatori di accesso per ulteriori informazioni.
Variabili locali
Usa la parola chiave Dim
per dichiarare una variabile locale :
Dim identifierName [As Type][, identifierName [As Type], ...]
La parte [As Type]
della sintassi della dichiarazione è facoltativa. Se specificato, imposta il tipo di dati della variabile, che determina la quantità di memoria che verrà allocata a tale variabile. Questo dichiara una variabile String
:
Dim identifierName As String
Quando un tipo non è specificato, il tipo è implicitamente Variant
:
Dim identifierName 'As Variant is implicit
La sintassi VBA supporta anche la dichiarazione di più variabili in una singola istruzione:
Dim someString As String, someVariant, someValue As Long
Si noti che [As Type]
deve essere specificato per ogni variabile (diversa da quelle 'Variant'). Questa è una trappola relativamente comune:
Dim integer1, integer2, integer3 As Integer 'Only integer3 is an Integer.
'The rest are Variant.
Variabili statiche
Le variabili locali possono anche essere Static
. In VBA la parola chiave Static
viene utilizzata per fare in modo che una variabile "ricordi" il valore che aveva, l'ultima volta che è stata chiamata una procedura:
Private Sub DoSomething()
Static values As Collection
If values Is Nothing Then
Set values = New Collection
values.Add "foo"
values.Add "bar"
End If
DoSomethingElse values
End Sub
Qui la collezione di values
è dichiarata come Locale Static
; perché è una variabile oggetto , è inizializzata su Nothing
. La condizione che segue la dichiarazione verifica se il riferimento all'oggetto è stato Set
precedenza - se è la prima volta che viene eseguita la procedura, la raccolta viene inizializzata. DoSomethingElse
potrebbe aggiungere o rimuovere elementi e saranno ancora presenti nella raccolta alla successiva chiamata a DoSomething
.
Alternativa
La parola chiave
Static
di VBA può essere facilmente fraintesa, specialmente da programmatori esperti che di solito lavorano in altre lingue. In molte lingue, lastatic
è usata per far sì che un membro della classe (campo, proprietà, metodo, ...) appartenga al tipo piuttosto che all'istanza . Il codice nel contestostatic
non può fare riferimento al codice nel contesto dell'istanza . La parola chiaveStatic
VBA significa qualcosa di molto diverso.
Spesso, un Static
locale potrebbe altrettanto bene essere implementato come un Private
variabile (campo), a livello di modulo - tuttavia questo sfida il principio secondo il quale una variabile deve essere dichiarata con il più piccolo campo di applicazione possibile; fidati del tuo istinto, usa quello che preferisci - entrambi funzioneranno ... ma usare Static
senza capire che cosa potrebbe portare a bug interessanti.
Dim vs. Privato
La parola chiave Dim
è legale a livello di procedura e modulo; il suo utilizzo a livello di modulo equivale all'utilizzo della parola chiave Private
:
Option Explicit
Dim privateField1 As Long 'same as Private privateField2 as Long
Private privateField2 As Long 'same as Dim privateField2 as Long
La parola chiave Private
è legale solo a livello di modulo; ciò invita a riservare Dim
per le variabili locali e a dichiarare le variabili del modulo con Private
, in particolare con la parola chiave Public
contrastante che dovrebbe essere comunque utilizzata per dichiarare un membro pubblico. In alternativa usa Dim
ovunque - ciò che conta è la coerenza :
"Campi privati"
- DO usa
Private
per dichiarare una variabile a livello di modulo. - USARE
Dim
per dichiarare una variabile locale. - NON usare
Dim
per dichiarare una variabile a livello di modulo.
"Dim ovunque"
- USARE
Dim
per dichiarare nulla private / locale. - NON usare
Private
per dichiarare una variabile a livello di modulo. - EVITARE la dichiarazione di campi
Public
. *
* In generale, si dovrebbe comunque evitare di dichiarare campi Public
o Global
.
campi
Una variabile dichiarata a livello di modulo, nella sezione delle dichiarazioni nella parte superiore del corpo del modulo, è un campo . Un campo Public
dichiarato in un modulo standard è una variabile globale :
Public PublicField As Long
È possibile accedere a una variabile con ambito globale da qualsiasi luogo, inclusi altri progetti VBA che facciano riferimento al progetto in cui è stato dichiarato.
Per rendere una variabile globale / pubblica, ma visibile solo all'interno del progetto, usa il modificatore Friend
:
Friend FriendField As Long
Ciò è particolarmente utile nei componenti aggiuntivi, dove l'intento è che altri progetti VBA facciano riferimento al progetto del componente aggiuntivo e possano utilizzare l'API pubblica.
Friend FriendField As Long 'public within the project, aka for "friend" code
Public PublicField As Long 'public within and beyond the project
I campi amici non sono disponibili nei moduli standard.
Campi di istanza
Una variabile dichiarata a livello di modulo, nella sezione delle dichiarazioni nella parte superiore del corpo di un modulo di classe (inclusi ThisWorkbook
, ThisDocument
, Worksheet
, UserForm
e moduli di classe ), è un campo di istanza : esiste solo finché c'è un'istanza di la classe in giro.
'> Class1
Option Explicit
Public PublicField As Long
'> Module1
Option Explicit
Public Sub DoSomething()
'Class1.PublicField means nothing here
With New Class1
.PublicField = 42
End With
'Class1.PublicField means nothing here
End Sub
Campi incapsulanti
I dati di istanza vengono spesso mantenuti Private
e duplicati incapsulati . Un campo privato può essere esposto utilizzando una procedura Property
. Per esporre una variabile privata pubblicamente senza fornire accesso in scrittura al chiamante, un modulo di classe (o un modulo standard) implementa un membro Property Get
:
Option Explicit
Private encapsulated As Long
Public Property Get SomeValue() As Long
SomeValue = encapsulated
End Property
Public Sub DoSomething()
encapsulated = 42
End Sub
La classe stessa può modificare il valore incapsulato, ma il codice chiamante può accedere solo ai membri Public
(e ai membri Friend
, se il chiamante si trova nello stesso progetto).
Per consentire al chiamante di modificare:
- Un valore incapsulato, un modulo espone un membro
Property Let
. - Un riferimento di oggetto incapsulato, un modulo espone un membro di
Property Set
.
Costanti (Const)
Se si dispone di un valore che non cambia mai nell'applicazione, è possibile definire una costante denominata e utilizzarla al posto di un valore letterale.
È possibile utilizzare Const solo a livello di modulo o procedura. Ciò significa che il contesto di dichiarazione per una variabile deve essere una classe, una struttura, un modulo, una procedura o un blocco e non può essere un file di origine, uno spazio dei nomi o un'interfaccia.
Public Const GLOBAL_CONSTANT As String = "Project Version #1.000.000.001"
Private Const MODULE_CONSTANT As String = "Something relevant to this Module"
Public Sub ExampleDeclaration()
Const SOME_CONSTANT As String = "Hello World"
Const PI As Double = 3.141592653
End Sub
Sebbene possa essere considerata una buona pratica specificare i tipi di Costante, non è strettamente necessario. Non specificando il tipo verrà comunque restituito il tipo corretto:
Public Const GLOBAL_CONSTANT = "Project Version #1.000.000.001" 'Still a string
Public Sub ExampleDeclaration()
Const SOME_CONSTANT = "Hello World" 'Still a string
Const DERIVED_CONSTANT = SOME_CONSTANT 'DERIVED_CONSTANT is also a string
Const VAR_CONSTANT As Variant = SOME_CONSTANT 'VAR_CONSTANT is Variant/String
Const PI = 3.141592653 'Still a double
Const DERIVED_PI = PI 'DERIVED_PI is also a double
Const VAR_PI As Variant = PI 'VAR_PI is Variant/Double
End Sub
Si noti che questo è specifico per le costanti e in contrasto con le variabili in cui non si specifica il tipo di risultati in un tipo Variant.
Mentre è possibile dichiarare esplicitamente una costante come String, non è possibile dichiarare una costante come una stringa usando la sintassi della stringa a larghezza fissa
'This is a valid 5 character string constant
Const FOO As String = "ABCDE"
'This is not valid syntax for a 5 character string constant
Const FOO As String * 5 = "ABCDE"
Modificatori di accesso
L'istruzione Dim
deve essere riservata alle variabili locali. A livello di modulo, preferisci i modificatori di accesso esplicito:
-
Private
per campi privati, a cui è possibile accedere solo all'interno del modulo in cui sono dichiarati. -
Public
per campi pubblici e variabili globali, a cui è possibile accedere tramite qualsiasi codice di chiamata. -
Friend
per le variabili pubbliche all'interno del progetto, ma inaccessibili ad altri progetti VBA di riferimento (rilevanti per i componenti aggiuntivi) -
Global
può essere utilizzato anche perPublic
campiPublic
in moduli standard, ma è illegale nei moduli di classe ed è comunque obsoleto - preferire invece il modificatorePublic
. Anche questo modificatore non è legale per le procedure.
I modificatori di accesso sono applicabili a variabili e procedure allo stesso modo.
Private ModuleVariable As String
Public GlobalVariable As String
Private Sub ModuleProcedure()
ModuleVariable = "This can only be done from within the same Module"
End Sub
Public Sub GlobalProcedure()
GlobalVariable = "This can be done from any Module within this Project"
End Sub
Opzione Modulo privato
Le procedure Sub
parametri pubbliche nei moduli standard sono esposte come macro e possono essere allegate ai comandi e alle scorciatoie da tastiera nel documento host.
Viceversa, le procedure di Function
pubblica nei moduli standard sono esposte come funzioni definite dall'utente (UDF) nell'applicazione host.
La specifica Option Private Module
nella parte superiore di un modulo standard impedisce ai suoi membri di essere esposti come macro e UDF all'applicazione host.
Tipo Suggerimenti
I suggerimenti di tipo sono fortemente scoraggiati. Esistono e sono documentati qui per motivi di compatibilità storica e retrocompatibile. Dovresti invece utilizzare la sintassi As [DataType]
.
Public Sub ExampleDeclaration()
Dim someInteger% '% Equivalent to "As Integer"
Dim someLong& '& Equivalent to "As Long"
Dim someDecimal@ '@ Equivalent to "As Currency"
Dim someSingle! '! Equivalent to "As Single"
Dim someDouble# '# Equivalent to "As Double"
Dim someString$ '$ Equivalent to "As String"
Dim someLongLong^ '^ Equivalent to "As LongLong" in 64-bit VBA hosts
End Sub
Gli hint del tipo riducono significativamente la leggibilità del codice e incoraggiano una notazione ungherese legacy che impedisce anche la leggibilità:
Dim strFile$
Dim iFile%
Invece, dichiarare le variabili più vicine al loro utilizzo e nominare le cose per quello che vengono utilizzate, non dopo il loro tipo:
Dim path As String
Dim handle As Integer
Gli hint di tipo possono essere utilizzati anche su letterali, per imporre un tipo specifico. Per impostazione predefinita, un valore letterale numerico inferiore a 32.768 verrà interpretato come un valore letterale Integer
, ma con un suggerimento sul tipo è possibile controllare che:
Dim foo 'implicit Variant
foo = 42& ' foo is now a Long
foo = 42# ' foo is now a Double
Debug.Print TypeName(42!) ' prints "Single"
Gli hint di tipo solitamente non sono necessari sui letterali, perché verrebbero assegnati a una variabile dichiarata con un tipo esplicito o convertiti implicitamente al tipo appropriato quando passati come parametri. Le conversioni implicite possono essere evitate usando una delle funzioni di conversione di tipo esplicito:
'Calls procedure DoSomething and passes a literal 42 as a Long using a type hint
DoSomething 42&
'Calls procedure DoSomething and passes a literal 42 explicitly converted to a Long
DoSomething CLng(42)
Funzioni built-in che restituiscono stringhe
La maggior parte delle funzioni integrate che gestiscono le stringhe sono disponibili in due versioni: una versione con caratteri generici che restituisce una Variant
e una versione fortemente tipizzata (che termina con $
) che restituisce una String
. A meno che non si assegni il valore restituito a una Variant
, è preferibile la versione che restituisce una String
, altrimenti esiste una conversione implicita del valore restituito.
Debug.Print Left(foo, 2) 'Left returns a Variant
Debug.Print Left$(foo, 2) 'Left$ returns a String
Queste funzioni sono:
- VBA.Conversion.Error -> VBA.Conversion.Error $
- VBA.Conversion.Hex -> VBA.Conversion.Hex $
- VBA.Conversion.Oct -> VBA.Conversion.Oct $
- VBA.Conversion.Str -> VBA.Conversion.Str $
- VBA.FileSystem.CurDir -> VBA.FileSystem.CurDir $
- VBA. [_ HiddenModule] .Input -> VBA. [_ HiddenModule] .Input $
- VBA. [_ HiddenModule] .InputB -> VBA. [_ HiddenModule] .InputB $
- VBA.Interaction.Command -> VBA.Interaction.Command $
- VBA.Interaction.Environ -> VBA.Interaction.Environ $
- VBA.Strings.Chr -> VBA.Strings.Chr $
- VBA.Strings.ChrB -> VBA.Strings.ChrB $
- VBA.Strings.ChrW -> VBA.Strings.ChrW $
- VBA.Strings.Format -> VBA.Strings.Format $
- VBA.Strings.LCase -> VBA.Strings.LCase $
- VBA.Strings.Left -> VBA.Strings.Left $
- VBA.Strings.LeftB -> VBA.Strings.LeftB $
- VBA.Strings.LTtrim -> VBA.Strings.LTrim $
- VBA.Strings.Mid -> VBA.Strings.Mid $
- VBA.Strings.MidB -> VBA.Strings.MidB $
- VBA.Strings.Right -> VBA.Strings.Right $
- VBA.Strings.RightB -> VBA.Strings.RightB $
- VBA.Strings.RTrim -> VBA.Strings.RTrim $
- VBA.Strings.Space -> VBA.Strings.Space $
- VBA.Strings.Str -> VBA.Strings.Str $
- VBA.Strings.String -> VBA.Strings.String $
- VBA.Strings.Trim -> VBA.Strings.Trim $
- VBA.Strings.UCase -> VBA.Strings.UCase $
Nota che questi sono alias di funzione, non del tutto tipi di suggerimenti . La funzione Left
corrisponde alla funzione nascosta B_Var_Left
, mentre la versione Left$
corrisponde alla funzione nascosta B_Str_Left
.
Nelle prime versioni di VBA il segno $
non è un carattere consentito e il nome della funzione doveva essere racchiuso tra parentesi quadre. In Word Basic c'erano molte, molte più funzioni che restituivano stringhe che terminavano in $.
Dichiarazione di stringhe a lunghezza fissa
In VBA, le stringhe possono essere dichiarate con una lunghezza specifica; vengono automaticamente riempiti o troncati per mantenere quella lunghezza dichiarata.
Public Sub TwoTypesOfStrings()
Dim FixedLengthString As String * 5 ' declares a string of 5 characters
Dim NormalString As String
Debug.Print FixedLengthString ' Prints " "
Debug.Print NormalString ' Prints ""
FixedLengthString = "123" ' FixedLengthString now equals "123 "
NormalString = "456" ' NormalString now equals "456"
FixedLengthString = "123456" ' FixedLengthString now equals "12345"
NormalString = "456789" ' NormalString now equals "456789"
End Sub
Quando usare una variabile statica
Una variabile statica dichiarata localmente non viene distrutta e non perde il suo valore quando si esce dalla procedura Sub. Le chiamate successive alla procedura non richiedono la reinizializzazione o l'assegnazione, sebbene sia possibile "azzerare" qualsiasi valore memorizzato.
Questi sono particolarmente utili quando legano in ritardo un oggetto in un sub "helper" che viene chiamato ripetutamente.
Frammento 1: riutilizzare un oggetto Scripting.Dictionary su più fogli di lavoro
Option Explicit
Sub main()
Dim w As Long
For w = 1 To Worksheets.Count
processDictionary ws:=Worksheets(w)
Next w
End Sub
Sub processDictionary(ws As Worksheet)
Dim i As Long, rng As Range
Static dict As Object
If dict Is Nothing Then
'initialize and set the dictionary object
Set dict = CreateObject("Scripting.Dictionary")
dict.CompareMode = vbTextCompare
Else
'remove all pre-existing dictionary entries
' this may or may not be desired if a single dictionary of entries
' from all worksheets is preferred
dict.RemoveAll
End If
With ws
'work with a fresh dictionary object for each worksheet
' without constructing/destructing a new object each time
' or do not clear the dictionary upon subsequent uses and
' build a dictionary containing entries from all worksheets
End With
End Sub
Snippet 2: crea un foglio di lavoro UDF che lega in ritardo l'oggetto VBScript.RegExp
Option Explicit
Function numbersOnly(str As String, _
Optional delim As String = ", ")
Dim n As Long, nums() As Variant
Static rgx As Object, cmat As Object
'with rgx as static, it only has to be created once
'this is beneficial when filling a long column with this UDF
If rgx Is Nothing Then
Set rgx = CreateObject("VBScript.RegExp")
Else
Set cmat = Nothing
End If
With rgx
.Global = True
.MultiLine = True
.Pattern = "[0-9]{1,999}"
If .Test(str) Then
Set cmat = .Execute(str)
'resize the nums array to accept the matches
ReDim nums(cmat.Count - 1)
'populate the nums array with the matches
For n = LBound(nums) To UBound(nums)
nums(n) = cmat.Item(n)
Next n
'convert the nums array to a delimited string
numbersOnly = Join(nums, delim)
Else
numbersOnly = vbNullString
End If
End With
End Function
Esempio di UDF con oggetto statico riempito attraverso mezzo milione di righe
* Tempi trascorsi per riempire righe da 500K con UDF: - con Dim rgx As Object : 148,74 secondi - con Statico rgx As Object : 26.07 secondi * Questi dovrebbero essere considerati solo per confronto relativo. I tuoi risultati varieranno in base alla complessità e
portata delle operazioni eseguite.
Ricorda che una UDF non viene calcolata una volta nella vita di una cartella di lavoro. Anche una UDF non volatile ricalcolerà ogni volta che i valori all'interno degli intervalli a cui fa riferimento sono soggetti a modifiche. Ogni evento di ricalcolo successivo aumenta solo i vantaggi di una variabile dichiarata staticamente.
- Una variabile statica è disponibile per la durata del modulo, non la procedura o la funzione in cui è stata dichiarata e assegnata.
- Le variabili statiche possono essere dichiarate solo localmente.
- Le variabili statiche contengono molte delle stesse proprietà di una variabile a livello di modulo privato ma con un ambito più limitato.
Riferimenti correlati: Statico (Visual Basic)