VBA
Förklarande variabler
Sök…
Implicit och eksplicit förklaring
Om en kodmodul inte innehåller Option Explicit
överst i modulen, kommer kompilatorn automatiskt (det vill säga "implicit") att skapa variabler för dig när du använder dem. De kommer som standard att variabel typ Variant
.
Public Sub ExampleDeclaration()
someVariable = 10 '
someOtherVariable = "Hello World"
'Both of these variables are of the Variant type.
End Sub
I koden ovan, om Option Explicit
är angivet, kommer koden att avbrytas eftersom den saknar de nödvändiga Dim
satserna för someVariable
och someOtherVariable
.
Option Explicit
Public Sub ExampleDeclaration()
Dim someVariable As Long
someVariable = 10
Dim someOtherVariable As String
someOtherVariable = "Hello World"
End Sub
Det anses vara bästa praxis att använda Option Explicit i kodmoduler för att säkerställa att du deklarerar alla variabler.
Se VBA Best Practices om hur du ställer in detta alternativ som standard.
variabler
Omfattning
En variabel kan deklareras (i ökande synbarhetsnivå):
- På procedurnivå använder du
Dim
nyckelordet i valfri procedur; en lokal variabel . - På modulnivå använder du det
Private
nyckelordet i alla typer av moduler; ett privat fält . - På instansnivå använder du nyckelordet
Friend
i alla typer av moduler; ett vänfält . - På instansnivå använder du det
Public
nyckelordet i alla typer av moduler; ett offentligt fält . - Globalt använder man det
Public
nyckelordet i en standardmodul ; en global variabel .
Variabler ska alltid deklareras med minsta möjliga omfattning: föredra att överföra parametrar till procedurer, snarare än att deklarera globala variabler.
Se Access Modifiers för mer information.
Lokala variabler
Använd nyckelordet Dim
att förklara en lokal variabel :
Dim identifierName [As Type][, identifierName [As Type], ...]
[As Type]
-delen i deklarationssyntaxen är valfri. När den anges anger den variabelns datatyp, som avgör hur mycket minne som ska tilldelas den variabeln. Detta förklarar en String
:
Dim identifierName As String
När en typ inte anges är typen implicit Variant
:
Dim identifierName 'As Variant is implicit
VBA-syntaxen stöder också att deklarera flera variabler i ett enda uttalande:
Dim someString As String, someVariant, someValue As Long
Lägg märke till att [As Type]
måste anges för varje variabel (utom "Variant"). Detta är en relativt vanlig fälla:
Dim integer1, integer2, integer3 As Integer 'Only integer3 is an Integer.
'The rest are Variant.
Statiska variabler
Lokala variabler kan också vara Static
. I VBA används det Static
nyckelordet för att göra en variabel "komma ihåg" det värde det hade, förra gången en procedur kallades:
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
Här values
samlingen deklareras som en Static
lokal; eftersom det är en objektvariabel , initialiseras den till Nothing
. Villkoret som följer deklarations verifierar om objektet Begäran har Set
innan - om det är första gången proceduren körs, blir samlingen initieras. DoSomethingElse
kanske lägger till eller tar bort objekt, och de kommer fortfarande att finnas i samlingen nästa gång DoSomething
heter.
Alternativ
VBA: s
Static
nyckelord kan lätt missförstås - särskilt av erfarna programmerare som vanligtvis fungerar på andra språk. På många språk användsstatic
för att få en klassmedlem (fält, egendom, metod, ...) tillhöra typen snarare än till instansen . Kod istatic
kontext kan inte hänvisa till kod i instanssammanhang .Static
nyckelordet VBA betyder något väldigt annorlunda.
Ofta kan en Static
lokal lika väl implementeras som en Private
, modulnivåvariabel (fält) - men detta utmanar principen med vilken en variabel bör deklareras med minsta möjliga räckvidd; lita på dina instinkter, använd vad du föredrar - båda kommer att fungera ... men om du använder Static
utan att förstå vad det gör kan det leda till intressanta buggar.
Dim kontra privat
Dim
nyckelordet är lagligt på procedur- och modulenivåer; dess användning på modulnivå motsvarar användningen av det Private
nyckelordet:
Option Explicit
Dim privateField1 As Long 'same as Private privateField2 as Long
Private privateField2 As Long 'same as Dim privateField2 as Long
Det Private
nyckelordet är endast lagligt på modulnivå; detta inbjuder till att reservera Dim
för lokala variabler och deklarera modulvariabler med Private
, särskilt med det kontrasterande Public
nyckelordet som måste användas ändå för att förklara en offentlig medlem. Alternativt kan du använda Dim
överallt - det som är viktigt är konsistens :
"Privata fält"
- Använd
Private
att deklarera en modulnivåvariabel. - Använd
Dim
att förklara en lokal variabel. - Använd INTE
Dim
att förklara en modulnivåvariabel.
"Dim överallt"
- Använd
Dim
att förklara allt privat / lokalt. - Använd INTE
Private
att deklarera en modulnivåvariabel. - UNDVIK att deklarera
Public
fält. *
* I allmänhet bör man i alla fall undvika att deklarera Public
eller Global
fält.
Fields
En variabel som deklareras på modulnivå, i deklarationsavsnittet högst upp på modulkroppen, är ett fält . Ett Public
fält som deklareras i en standardmodul är en global variabel :
Public PublicField As Long
En variabel med en global räckvidd kan nås var som helst, inklusive andra VBA-projekt som skulle hänvisa till det projekt som det förklaras i.
För att göra en variabel global / offentlig men endast synlig från projektet använder du Friend
modifieraren:
Friend FriendField As Long
Detta är särskilt användbart i tillägg, där avsikten är att andra VBA-projekt hänvisar till tilläggsprojektet och kan konsumera det offentliga API: et.
Friend FriendField As Long 'public within the project, aka for "friend" code
Public PublicField As Long 'public within and beyond the project
Vänfält är inte tillgängliga i standardmoduler.
Instansfält
En variabel som deklareras på modulnivå, i deklarationsavsnittet högst upp i kroppen på en ThisWorkbook
(inklusive ThisWorkbook
, ThisDocument
, Worksheet
, UserForm
och class modules ), är ett instansfält : det finns bara så länge det finns en instans av klassen runt.
'> 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
Inkapsling av fält
Instansdata hålls ofta Private
och dubblas inkapslade . Ett privat fält kan exponeras med hjälp av ett Property
. För att exponera en privat variabel offentligt utan att ge skrivtillgång till den som ringer, implementerar en klassmodul (eller en standardmodul) en Property Get
medlem:
Option Explicit
Private encapsulated As Long
Public Property Get SomeValue() As Long
SomeValue = encapsulated
End Property
Public Sub DoSomething()
encapsulated = 42
End Sub
Klassen själv kan ändra det inkapslade värdet, men samtalskoden har bara åtkomst till de Public
medlemmarna (och Friend
om den som ringer i samma projekt).
För att låta den som ringer ändra:
- Ett inkapslat värde , en modul visar en
Property Let
medlem. - En inkapslad objektreferens , en modul visar en
Property Set
medlem.
Konstanter (Const)
Om du har ett värde som aldrig ändras i din applikation kan du definiera en namngivna konstant och använda den istället för ett bokstavligt värde.
Du kan bara använda Const på modul- eller procedurnivå. Detta innebär att deklarationskonteksten för en variabel måste vara en klass, struktur, modul, procedur eller block, och kan inte vara en källfil, namnutrymme eller gränssnitt.
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
Även om det kan betraktas som god praxis att specificera konstanttyper, krävs det inte strikt. Att inte ange typen kommer fortfarande att resultera i rätt typ:
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
Observera att detta är specifikt för konstanter och i motsats till variabler där man inte specificerar typen resulterar i en varianttyp.
Även om det är möjligt att uttryckligen deklarera en konstant som en sträng, är det inte möjligt att deklarera en konstant som en sträng med hjälp av syntax med fast breddsträng
'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"
Tillgång modifierare
Dim
satsen ska reserveras för lokala variabler. På modulnivå föredrar du explicita åtkomstmodifierare:
-
Private
för privata fält, som bara kan nås inom den modul de deklareras i. -
Public
för offentliga fält och globala variabler, som kan nås med valfri samtalskod. -
Friend
för variabler som är offentliga inom projektet, men otillgängliga för andra referens VBA-projekt (relevant för tillägg) -
Global
kan också användas förPublic
fält i standardmoduler, men är olagligt i klassmoduler och föråldrad ändå - föredrar istället denPublic
modifieraren. Den här modifieraren är inte heller laglig för procedurer.
Tillgångsmodifierare är tillämpliga på både variabler och procedurer.
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
Alternativ privat modul
Offentliga parameterlösa Sub
i standardmoduler exponeras som makron och kan anslutas till kontroller och kortkommandon i värddokumentet.
Omvänt exponeras offentliga Function
i standardmoduler som användardefinierade funktioner (UDF: er) i värdapplikationen.
Att ange Option Private Module
längst upp i en standardmodul förhindrar dess medlemmar från att exponeras som makron och UDF: er för värdapplikationen.
Skriv tips
Typtips är starkt avskräckta. De finns och dokumenteras här av historiska skäl och bakåtkompatibilitetsskäl. Du bör använda syntaxen As [DataType]
istället.
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
Typtips minskar kodens läsbarhet avsevärt och uppmuntrar en gammal ungersk notation som också hindrar läsbarheten:
Dim strFile$
Dim iFile%
Förklar istället variabler närmare deras användning och namnge saker för vad de används, inte efter deras typ:
Dim path As String
Dim handle As Integer
Typtips kan också användas på bokstäver för att upprätthålla en specifik typ. Som standard kommer en numerisk bokstav som är mindre än 32 768 att tolkas som ett Integer
, men med en typtipp kan du kontrollera att:
Dim foo 'implicit Variant
foo = 42& ' foo is now a Long
foo = 42# ' foo is now a Double
Debug.Print TypeName(42!) ' prints "Single"
Typtips behövs vanligtvis inte på bokstäver, eftersom de skulle tilldelas en variabel som deklareras med en uttrycklig typ eller implicit konverteras till lämplig typ när den skickas som parametrar. Implicita konverteringar kan undvikas med hjälp av en av de explicita konverteringsfunktionerna:
'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)
Strängåtervända inbyggda funktioner
Majoriteten av de inbyggda funktionerna som hanterar strängar finns i två versioner: En löst typad version som returnerar en Variant
och en starkt typad version (som slutar med $
) som returnerar en String
. Om du inte tilldelar returvärdet till en Variant
, bör du föredra den version som returnerar en String
- annars är det en implicit konvertering av returvärdet.
Debug.Print Left(foo, 2) 'Left returns a Variant
Debug.Print Left$(foo, 2) 'Left$ returns a String
Dessa funktioner är:
- 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 $
Observera att dessa är funktions alias, inte riktigt skriva tips. Den Left
funktionen motsvarar den dolda B_Var_Left
funktionen, medan den Left$
-versionen motsvarar den dolda B_Str_Left
funktionen.
I mycket tidiga versioner av VBA är $
-tecknet inte ett tillåtet tecken och funktionsnamnet måste bifogas i fyrkantiga parenteser. I Word Basic fanns det många, många fler funktioner som returnerade strängar som slutade på $.
Förklarar fast längdsträngar
I VBA kan strängar deklareras med en viss längd; de är automatiskt vadderade eller trunkerade för att bibehålla den längden som deklarerats.
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
När man ska använda en statisk variabel
En statisk variabel som deklareras lokalt förstörs inte och förlorar inte sitt värde när Sub-proceduren avslutas. Efterföljande samtal till proceduren kräver inte ominitialisering eller tilldelning, även om du kanske vill "nollställa" alla minnda värden.
Dessa är särskilt användbara när man för sent binder ett föremål i en "hjälpar" sub som kallas upprepade gånger.
Utdrag 1: Återanvänd ett Scripting.Diction-objekt i många kalkylblad
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
Utdrag 2: Skapa ett arbetsblad UDF som sent binder VBScript.RegExp-objektet
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
Exempel på UDF med statiska objekt fyllda en halv miljon rader
* Förflutna tider för att fylla 500K rader med UDF: - med Dim rgx som objekt : 148,74 sekunder - med statisk rgx som objekt : 26,07 sekunder * Dessa bör endast beaktas för relativ jämförelse. Dina egna resultat kommer att variera beroende på komplexitet och
omfattning av utförda operationer.
Kom ihåg att en UDF inte beräknas en gång under en arbetsbok. Även en icke-flyktig UDF kommer att beräkna om varje gång värdena inom det / de områden som den refererar kan ändras. Varje efterföljande omberäkningshändelse ökar bara fördelarna med en statiskt deklarerad variabel.
- En statisk variabel är tillgänglig för modulens livstid, inte proceduren eller funktionen där den förklarades och tilldelades.
- Statiska variabler kan endast deklareras lokalt.
- Statisk variabel har många av samma egenskaper för en privat modulnivåvariabel men med ett mer begränsat omfattning.
Relaterad referens: Statisk (Visual Basic)