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
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 wordtstatic
gebruikt om ervoor te zorgen dat een lid van de klasse (veld, eigenschap, methode, ...) tot het type behoort en niet tot de instantie . Code instatic
context kan niet verwijzen naar code in bijvoorbeeld context. Het VBAStatic
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 voorPublic
velden in standaardmodules, maar is illegaal in klassemodules en is hoe dan ook verouderd - geef in plaats daarvan de voorkeur aan dePublic
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
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)