VBA
Variabelen declareren
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
Dimin elke procedure; een lokale variabele . - Op moduleniveau, met behulp van het trefwoord
Privatein elk type module; een privéveld . - Op instantieniveau, met behulp van het trefwoord
Friendin elk type klassemodule; een vriendenveld . - Op instantieniveau, met behulp van het trefwoord
Publicin elk type klassemodule; een openbaar veld . - Wereldwijd met behulp van het trefwoord
Publicin 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
Statictrefwoord van VBA kan gemakkelijk verkeerd worden begrepen - vooral door ervaren programmeurs die meestal in andere talen werken. In veel talen wordtstaticgebruikt om ervoor te zorgen dat een lid van de klasse (veld, eigenschap, methode, ...) tot het type behoort en niet tot de instantie . Code instaticcontext kan niet verwijzen naar code in bijvoorbeeld context. Het VBAStatictrefwoord 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
Privateom een variabele op moduleniveau te declareren. - Gebruik
Dimom een lokale variabele te declareren. - Gebruik NIET
Dimom een variabele op moduleniveau te declareren.
"Overal dimmen"
- Gebruik
Dimom alles privé / lokaal te verklaren. - Gebruik GEEN
Privateom een variabele op moduleniveau te declareren. - VERMIJD het aangeven van
Publicvelden. *
* 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 Letlid. - 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:
-
Privatevoor privévelden, die alleen toegankelijk zijn binnen de module waarin ze zijn aangegeven. -
Publicvoor openbare velden en globale variabelen, die toegankelijk zijn met elke belcode. -
Friendvoor openbare variabelen binnen het project, maar ontoegankelijk voor andere VBA-projecten waarnaar wordt verwezen (relevant voor invoegtoepassingen) -
Globalkan ook worden gebruikt voorPublicvelden in standaardmodules, maar is illegaal in klassemodules en is hoe dan ook verouderd - geef in plaats daarvan de voorkeur aan dePublicmodifier. 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
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)