Zoeken…


Impliciete en expliciete verklaring

Als een codemodule geen Option Explicit boven aan de module bevat, maakt de compiler automatisch (dat wil zeggen "impliciet") variabelen voor u wanneer u ze gebruikt. Ze worden standaard ingesteld op Varianttype Variant .

Public Sub ExampleDeclaration()    

    someVariable = 10                  ' 
    someOtherVariable = "Hello World"
    'Both of these variables are of the Variant type.

End Sub

Als in de bovenstaande code Option Explicit is opgegeven, wordt de code onderbroken omdat de vereiste Dim instructies ontbreken voor someVariable en someOtherVariable .

Option Explicit

Public Sub ExampleDeclaration()   

    Dim someVariable As Long 
    someVariable = 10

    Dim someOtherVariable As String
    someOtherVariable = "Hello World"

End Sub

Het wordt als beste praktijk beschouwd om Option Explicit in codemodules te gebruiken, om ervoor te zorgen dat u alle variabelen opgeeft.

Zie VBA Best Practices hoe u deze optie standaard kunt instellen.

Variabelen

strekking

Een variabele kan worden gedeclareerd (in toenemend zichtbaarheidsniveau):

  • Op procedureniveau, met behulp van het trefwoord Dim in elke procedure; een lokale variabele .
  • Op moduleniveau, met behulp van het trefwoord Private in elk type module; een privéveld .
  • Op instantieniveau, met behulp van het trefwoord Friend in elk type klassemodule; een vriendenveld .
  • Op instantieniveau, met behulp van het trefwoord Public in elk type klassemodule; een openbaar veld .
  • Wereldwijd met behulp van het trefwoord Public in een standaardmodule ; een globale variabele .

Variabelen moeten altijd met de kleinst mogelijke reikwijdte worden gedeclareerd: geef de voorkeur aan het doorgeven van parameters boven procedures, in plaats van algemene variabelen.

Zie Toegangsmodificaties voor meer informatie.


Lokale variabelen

Gebruik het trefwoord Dim om een lokale variabele te declareren:

Dim identifierName [As Type][, identifierName [As Type], ...]

Het gedeelte [As Type] van de syntaxis van de aangifte is optioneel. Wanneer opgegeven, wordt het gegevenstype van de variabele ingesteld, dat bepaalt hoeveel geheugen aan die variabele wordt toegewezen. Dit verklaart een String variabele:

Dim identifierName As String

Wanneer een type niet is opgegeven, is het type impliciet Variant :

Dim identifierName 'As Variant is implicit

De VBA-syntaxis ondersteunt ook het declareren van meerdere variabelen in een enkele instructie:

Dim someString As String, someVariant, someValue As Long

Merk op dat het [As Type] moet worden gespecificeerd voor elke variabele (anders dan 'Variant'). Dit is een relatief veel voorkomende valkuil:

Dim integer1, integer2, integer3 As Integer 'Only integer3 is an Integer. 
                                            'The rest are Variant.

Statische variabelen

Lokale variabelen kunnen ook Static . In VBA wordt het Static trefwoord gebruikt om een variabele de waarde te laten "onthouden" die hij had, de vorige keer dat een procedure werd genoemd:

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

Hier wordt de verzameling values gedeclareerd als een Static local; omdat het een objectvariabele is , wordt deze geïnitialiseerd op Nothing . De voorwaarde die volgt op de verklaring verifieert of de objectreferentie eerder was Set - als het de eerste keer is dat de procedure wordt uitgevoerd, wordt de verzameling geïnitialiseerd. DoSomethingElse mogelijk items toe of verwijdert deze, en de volgende keer dat DoSomething wordt aangeroepen, staan ze nog in de verzameling.

Alternatief

Het Static trefwoord van VBA kan gemakkelijk verkeerd worden begrepen - vooral door ervaren programmeurs die meestal in andere talen werken. In veel talen wordt static gebruikt om ervoor te zorgen dat een lid van de klasse (veld, eigenschap, methode, ...) tot het type behoort en niet tot de instantie . Code in static context kan niet verwijzen naar code in bijvoorbeeld context. Het VBA Static trefwoord betekent iets heel anders.

Vaak kan een Static local net zo goed worden geïmplementeerd als een Private , module-variabele (veld) - maar dit betwist het principe waarmee een variabele met de kleinst mogelijke reikwijdte moet worden gedeclareerd; vertrouw op je instinct, gebruik wat je maar wilt - beide zullen werken ... maar het gebruik van Static zonder te begrijpen wat het doet, kan tot interessante bugs leiden.


Dim versus privé

Het Dim trefwoord is legaal op procedure- en moduleniveau; het gebruik op moduleniveau is gelijk aan het gebruik van het Private sleutelwoord:

Option Explicit
Dim privateField1 As Long 'same as Private privateField2 as Long
Private privateField2 As Long 'same as Dim privateField2 as Long

Het Private trefwoord is alleen legaal op moduleniveau; dit nodigt uit om Dim te reserveren voor lokale variabelen en modulevariabelen te declareren met Private , vooral met het contrasterende Public sleutelwoord dat toch zou moeten worden gebruikt om een publiek lid te verklaren. Of gebruik Dim overal - het gaat om consistentie :

"Privé velden"

  • Gebruik Private om een variabele op moduleniveau te declareren.
  • Gebruik Dim om een lokale variabele te declareren.
  • Gebruik NIET Dim om een variabele op moduleniveau te declareren.

"Overal dimmen"

  • Gebruik Dim om alles privé / lokaal te verklaren.
  • Gebruik GEEN Private om een variabele op moduleniveau te declareren.
  • VERMIJD het aangeven van Public velden. *

* Over het algemeen moet men toch vermijden om Public of Global velden aan te geven.


Fields

Een variabele die op moduleniveau wordt gedeclareerd, in het gedeelte met verklaringen bovenaan de module, is een veld . Een Public veld dat in een standaardmodule wordt aangegeven, is een globale variabele :

Public PublicField As Long

Een variabele met een wereldwijd bereik is overal toegankelijk, inclusief andere VBA-projecten die verwijzen naar het project waarin het wordt vermeld.

Gebruik de Friend modifier om een variabele algemeen / openbaar te maken, maar alleen zichtbaar vanuit het project:

Friend FriendField As Long

Dit is vooral handig in invoegtoepassingen, waarbij de bedoeling is dat andere VBA-projecten verwijzen naar het invoegtoepassingsproject en de openbare API kunnen gebruiken.

Friend FriendField As Long 'public within the project, aka for "friend" code
Public PublicField As Long 'public within and beyond the project

Vriendvelden zijn niet beschikbaar in standaardmodules.


Instantievelden

Een variabele gedeclareerd op moduleniveau in de Speciale Voorwaarden bovenaan het lichaam van een klassenmodule (inclusief ThisWorkbook , ThisDocument , Worksheet , UserForm en klassemodules), een instantieveld: alleen bestaat zolang er een voorbeeld van de klas rond.

'> 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

Inkapselende velden

Instantiegegevens worden vaak Private gehouden en ingekapseld nagesynchroniseerd. Een privéveld kan worden blootgesteld met een Property . Om een privévariabele openbaar te maken zonder schrijftoegang te geven aan de beller, implementeert een klassemodule (of een standaardmodule) een Property Get lid:

Option Explicit
Private encapsulated As Long

Public Property Get SomeValue() As Long
    SomeValue = encapsulated
End Property

Public Sub DoSomething()
    encapsulated = 42
End Sub

De klasse zelf kan de ingekapselde waarde wijzigen, maar de oproepcode heeft alleen toegang tot de Public leden (en Friend als de beller in hetzelfde project zit).

De beller toestaan om te wijzigen:

  • Een ingekapselde waarde , een module toont een Property Let lid.
  • Een ingekapselde objectreferentie , een module toont een lid van de Property Set .

Constanten (Const)

Als u een waarde heeft die nooit verandert in uw toepassing, kunt u een benoemde constante definiëren en deze gebruiken in plaats van een letterlijke waarde.

U kunt Const alleen op module- of procedureniveau gebruiken. Dit betekent dat de declaratiecontext voor een variabele een klasse, structuur, module, procedure of blok moet zijn en geen bronbestand, naamruimte of interface mag zijn.

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

Hoewel het als een goede praktijk kan worden beschouwd om Constant-typen te specificeren, is dit niet strikt vereist. Als u het type niet opgeeft, krijgt u nog steeds het juiste type:

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

Merk op dat dit specifiek is voor Constanten en in tegenstelling tot variabelen waar het niet specificeren van het type resulteert in een Variant-type.

Hoewel het mogelijk is om een constante expliciet als een string te declareren, is het niet mogelijk om een constante als een string te declareren met een syntaxis met een vaste breedte

'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"

Toegang tot modificaties

De Dim instructie moet worden gereserveerd voor lokale variabelen. Geef op moduleniveau de voorkeur aan expliciete toegangsmodificaties:

  • Private voor privévelden, die alleen toegankelijk zijn binnen de module waarin ze zijn aangegeven.
  • Public voor openbare velden en globale variabelen, die toegankelijk zijn met elke belcode.
  • Friend voor openbare variabelen binnen het project, maar ontoegankelijk voor andere VBA-projecten waarnaar wordt verwezen (relevant voor invoegtoepassingen)
  • Global kan ook worden gebruikt voor Public velden in standaardmodules, maar is illegaal in klassemodules en is hoe dan ook verouderd - geef in plaats daarvan de voorkeur aan de Public modifier. Deze modifier is ook niet legaal voor procedures.

Toegangsmodificeerders zijn van toepassing op zowel variabelen als procedures.

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

Optie privémodule

Openbare parameterloze Sub procedures in standaardmodules worden weergegeven als macro's en kunnen worden gekoppeld aan besturingselementen en sneltoetsen in het hostdocument.

Omgekeerd worden openbare Function in standaardmodules blootgesteld als door de gebruiker gedefinieerde functies (UDF's) in de hosttoepassing.

Als u Option Private Module boven aan een standaardmodule opgeeft, wordt voorkomen dat zijn leden als macro's en UDF's worden blootgesteld aan de hosttoepassing.

Type Tips

Type Hints worden sterk afgeraden. Ze bestaan en worden hier gedocumenteerd om historische en achterwaartse compatibiliteitsredenen. Gebruik in plaats daarvan de syntaxis 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

Type-tips verminderen de leesbaarheid van de code aanzienlijk en moedigen een oude Hongaarse notatie aan die ook de leesbaarheid belemmert:

Dim strFile$
Dim iFile%

Verklaar in plaats daarvan variabelen die dichter bij hun gebruik liggen en noem dingen voor wat ze gebruiken, niet na hun type:

Dim path As String
Dim handle As Integer

Typehints kunnen ook worden gebruikt voor letterlijke tekens om een specifiek type af te dwingen. Standaard wordt een numeriek letterlijk kleiner dan 32.768 geïnterpreteerd als een geheel Integer letterlijk, maar met een typehint kunt u dat regelen:

Dim foo 'implicit Variant
foo = 42& ' foo is now a Long
foo = 42# ' foo is now a Double
Debug.Print TypeName(42!) ' prints "Single"

Typehints zijn meestal niet nodig voor letterlijke tekens, omdat ze zouden worden toegewezen aan een variabele die met een expliciet type wordt gedeclareerd, of impliciet in het juiste type wordt omgezet als ze als parameters worden doorgegeven. Impliciete conversies kunnen worden vermeden met behulp van een van de expliciete conversiefuncties:

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

String-terugkerende ingebouwde functies

De meeste ingebouwde functies die tekenreeksen verwerken, zijn er in twee versies: een los getypte versie die een Variant retourneert en een sterk getypte versie (eindigend op $ ) die een String retourneert. Tenzij u de retourwaarde aan een Variant toewijst, moet u de voorkeur geven aan de versie die een String retourneert - anders is er een impliciete conversie van de retourwaarde.

Debug.Print Left(foo, 2)  'Left returns a Variant
Debug.Print Left$(foo, 2) 'Left$ returns a String

Deze functies zijn:

  • 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 $

Merk op dat dit functie- aliassen zijn , geen typetips . De functie Left komt overeen met de verborgen functie B_Var_Left , terwijl de versie Left$ overeenkomt met de functie verborgen B_Str_Left .

In zeer vroege versies van VBA is het $ -teken geen toegestaan teken en moest de functienaam tussen vierkante haken worden geplaatst. In Word Basic waren er veel, veel meer functies die tekenreeksen opleverden die eindigden op $.

Strings met vaste lengte declareren

In VBA kunnen tekenreeksen met een specifieke lengte worden aangegeven; ze worden automatisch opgevuld of afgekapt om die lengte te behouden zoals aangegeven.

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

Wanneer een statische variabele te gebruiken

Een lokaal gedeclareerde variabele wordt niet vernietigd en verliest zijn waarde niet wanneer de Sub-procedure wordt afgesloten. Latere aanroepen van de procedure vereisen geen herinitialisatie of toewijzing, hoewel u eventueel herinnerde waarde (n) wilt 'nul'en.

Deze zijn met name handig wanneer een object laat wordt ingebonden in een 'helper'-sub die herhaaldelijk wordt aangeroepen.

Fragment 1: gebruik een Scripting.Dictionary-object over meerdere werkbladen

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

Fragment 2: maak een werkblad-UDF die het VBScript.RegExp-object laat bindt

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
Voorbeeld van UDF met statisch object gevuld door een half miljoen rijen

* Verstreken tijden om 500K rijen te vullen met UDF:
- met Dim rgx als object : 148,74 seconden
- met statische rgx als object : 26,07 seconden
* Deze moeten alleen worden overwogen voor relatieve vergelijking. Uw eigen resultaten variëren afhankelijk van de complexiteit en
omvang van de uitgevoerde operaties.

Vergeet niet dat een UDF niet één keer tijdens de levensduur van een werkmap wordt berekend. Zelfs een niet-vluchtige UDF zal opnieuw worden berekend wanneer de waarden binnen het bereik waarnaar deze verwijst, kunnen veranderen. Elke volgende herberekeningsgebeurtenis verhoogt alleen de voordelen van een statisch aangegeven variabele.

  • Een statische variabele is beschikbaar voor de levensduur van de module, niet de procedure of functie waarin deze is gedeclareerd en toegewezen.
  • Statische variabelen kunnen alleen lokaal worden gedeclareerd.
  • Statische variabele bevat veel van dezelfde eigenschappen van een variabele op privé-moduleniveau, maar met een beperkter bereik.

Verwante verwijzing: Statisch (Visual Basic)



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow