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änds static för att få en klassmedlem (fält, egendom, metod, ...) tillhöra typen snarare än till instansen . Kod i static 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ör Public fält i standardmoduler, men är olagligt i klassmoduler och föråldrad ändå - föredrar istället den Public 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

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



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow