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, la static è usata per far sì che un membro della classe (campo, proprietà, metodo, ...) appartenga al tipo piuttosto che all'istanza . Il codice nel contesto static non può fare riferimento al codice nel contesto dell'istanza . La parola chiave Static 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 per Public campi Public in moduli standard, ma è illegale nei moduli di classe ed è comunque obsoleto - preferire invece il modificatore Public . 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

static_UDF
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)



Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow