Szukaj…


Oświadczenie niejawne i wyraźne

Jeśli moduł kodu nie zawiera Option Explicit w górnej części modułu, wówczas kompilator automatycznie (tj. „Niejawnie”) utworzy dla ciebie zmienne, gdy ich użyjesz. Domyślnie zostaną zmienne typu Variant .

Public Sub ExampleDeclaration()    

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

End Sub

W powyższym kodzie, jeśli podano Option Explicit , kod przerwie, ponieważ brakuje wymaganych instrukcji Dim dla someVariable i someOtherVariable .

Option Explicit

Public Sub ExampleDeclaration()   

    Dim someVariable As Long 
    someVariable = 10

    Dim someOtherVariable As String
    someOtherVariable = "Hello World"

End Sub

Za najlepszą praktykę uważa się stosowanie opcji Explicit w modułach kodu, aby zapewnić zadeklarowanie wszystkich zmiennych.

Zobacz Najważniejsze wskazówki VBA, jak ustawić tę opcję domyślnie.

Zmienne

Zakres

Zmienna może być zadeklarowana (przy wzroście poziomu widoczności):

  • Na poziomie procedury za pomocą słowa kluczowego Dim w dowolnej procedurze; zmienna lokalna .
  • Na poziomie modułu przy użyciu słowa kluczowego Private w dowolnym typie modułu; prywatne pole .
  • Na poziomie instancji za pomocą słowa kluczowego Friend w dowolnym typie modułu klasy; pole przyjaciela .
  • Na poziomie instancji przy użyciu słowa kluczowego Public w dowolnym typie modułu klasy; pole publiczne .
  • Globalnie, używając słowa kluczowego Public w standardowym module ; zmienna globalna .

Zmienne powinny zawsze być deklarowane w możliwie najmniejszym zakresie: wolą przekazywać parametry niż procedury, niż deklarować zmienne globalne.

Aby uzyskać więcej informacji, zobacz Modyfikatory dostępu .


Zmienne lokalne

Użyj słowa kluczowego Dim aby zadeklarować zmienną lokalną :

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

Część [As Type] składni deklaracji jest opcjonalna. Po określeniu ustawia typ danych zmiennej, który określa, ile pamięci zostanie przydzielone do tej zmiennej. To deklaruje zmienną String :

Dim identifierName As String

Jeśli typ nie jest określony, typ jest domyślnie Variant :

Dim identifierName 'As Variant is implicit

Składnia VBA obsługuje również deklarowanie wielu zmiennych w jednej instrukcji:

Dim someString As String, someVariant, someValue As Long

Zauważ, że [As Type] należy podać dla każdej zmiennej (innej niż „Variant”). Jest to stosunkowo powszechna pułapka:

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

Zmienne statyczne

Zmienne lokalne mogą być również Static . W języku VBA słowo kluczowe Static służy do tego, aby zmienna „zapamiętywała” wartość, jaką miała, przy ostatnim wywołaniu procedury:

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

Tutaj zbiór values jest zadeklarowany jako lokalny Static ; ponieważ jest to zmienna obiektowa , jest inicjowana na wartość Nothing . Warunek następujący po deklaracji sprawdza, czy odwołanie do obiektu było Set wcześniej - jeśli procedura jest uruchamiana po raz pierwszy, kolekcja jest inicjowana. DoSomethingElse może dodawać lub usuwać elementy i będą one nadal w kolekcji przy następnym wywołaniu DoSomething .

Alternatywny

Static słowo kluczowe VBA może być łatwo źle zrozumiane - szczególnie przez doświadczonych programistów, którzy zwykle pracują w innych językach. W wielu językach static służy do tego, aby element klasy (pole, właściwość, metoda, ...) należał do typu, a nie do instancji . Kod w kontekście static nie może odwoływać się do kodu w kontekście instancji . Słowo kluczowe VBA Static oznacza coś zupełnie innego.

Często Static lokalny może być równie dobrze zaimplementowany jak Private zmienna na poziomie modułu (pole) - jednak podważa to zasadę, według której zmienna powinna być deklarowana w możliwie najmniejszym zakresie; zaufaj instynktowi, użyj tego, co wolisz - oba będą działać ... ale używanie Static bez zrozumienia, co to może prowadzić do interesujących błędów.


Dim vs. Private

Dim kluczowe Dim jest legalne na poziomie procedury i modułu; jego użycie na poziomie modułu jest równoważne użyciu słowa kluczowego Private :

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

Private słowo kluczowe jest legalne tylko na poziomie modułu; zachęca to do zarezerwowania Dim dla zmiennych lokalnych i zadeklarowania zmiennych modułu za pomocą Private , szczególnie z kontrastującym słowem kluczowym Public , którego i tak należałoby użyć, aby zadeklarować członka publicznego. Alternatywnie używaj Dim wszędzie - ważna jest spójność :

„Pola prywatne”

  • NALEŻY używać Private do deklarowania zmiennej na poziomie modułu.
  • NIE używaj Dim do deklarowania zmiennej lokalnej.
  • NIE używaj Dim do deklarowania zmiennej na poziomie modułu.

„Przyciemnij wszędzie”

  • NIE używaj Dim do deklarowania czegokolwiek prywatnego / lokalnego.
  • NIE używaj Private do deklarowania zmiennej na poziomie modułu.
  • UNIKAJ deklarowania pól Public . *

* Zasadniczo należy unikać deklarowania pól Public lub Global .


Fields

Zmienna zadeklarowana na poziomie modułu, w sekcji deklaracji u góry treści modułu, jest polem . Pole Public zadeklarowane w module standardowym jest zmienną globalną :

Public PublicField As Long

Dostęp do zmiennej o zasięgu globalnym można uzyskać z dowolnego miejsca, w tym z innych projektów VBA, które odwoływałyby się do projektu, w którym zostały zadeklarowane.

Aby ustawić zmienną globalną / publiczną, ale widoczną tylko z poziomu projektu, użyj modyfikatora Friend :

Friend FriendField As Long

Jest to szczególnie przydatne w dodatkach, gdzie celem jest, aby inne projekty VBA odwoływały się do projektu dodatku i mogły korzystać z publicznego interfejsu API.

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

Pola znajomych nie są dostępne w standardowych modułach.


Pola wystąpienia

Zmienna zadeklarowana na poziomie modułu, w sekcji deklaracji u góry treści modułu klasy (w tym ThisWorkbook , ThisDocument , Worksheet , UserForm i moduły klas ), jest polem instancji : istnieje tylko tak długo, jak długo istnieje instancja klasa wokół.

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

Hermetyzowanie pól

Dane instancji są często przechowywane w trybie Private i są kopiowane w sposób enkapsulowany . Pole prywatne można odsłonić za pomocą procedury Property . Aby publicznie udostępnić zmienną prywatną bez umożliwienia zapisu do osoby wywołującej, moduł klasy (lub moduł standardowy) implementuje członka Property Get :

Option Explicit
Private encapsulated As Long

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

Public Sub DoSomething()
    encapsulated = 42
End Sub

Sama klasa może modyfikować zawartą w sobie wartość, ale kod wywołujący może uzyskiwać dostęp tylko do członków Public (i członków Friend , jeśli osoba dzwoniąca jest w tym samym projekcie).

Aby zezwolić dzwoniącemu na modyfikację:

  • Hermetyzowana wartość , moduł ujawnia element Property Let .
  • W enkapsulowanym odwołaniu do obiektu moduł ujawnia element Property Set .

Stałe (Const)

Jeśli masz wartość, która nigdy się nie zmienia w aplikacji, możesz zdefiniować nazwaną stałą i użyć jej zamiast wartości dosłownej.

Możesz używać Const tylko na poziomie modułu lub procedury. Oznacza to, że kontekst deklaracji dla zmiennej musi być klasą, strukturą, modułem, procedurą lub blokiem i nie może być plikiem źródłowym, przestrzenią nazw ani interfejsem.

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

Chociaż określenie typów stałych można uznać za dobrą praktykę, nie jest to bezwzględnie wymagane. Nieokreślenie typu będzie nadal skutkować poprawnym typem:

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

Zauważ, że jest to specyficzne dla Stałych i w przeciwieństwie do zmiennych, w których nieokreślenie typu powoduje powstanie typu Wariant.

Chociaż można jawnie zadeklarować stałą jako ciąg, nie jest możliwe zadeklarowanie stałej jako ciąg przy użyciu składni ciągu o stałej szerokości

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

Modyfikatory dostępu

Instrukcja Dim powinna być zarezerwowana dla zmiennych lokalnych. Na poziomie modułu preferuj modyfikatory dostępu bezpośredniego:

  • Private dla pól prywatnych, do których można uzyskać dostęp tylko w module, w którym zostały zadeklarowane.
  • Public dla pól publicznych i zmiennych globalnych, do których można uzyskać dostęp za pomocą dowolnego kodu wywołującego.
  • Friend zmiennych zmiennych publicznych w projekcie, ale niedostępny dla innych projektów VBA odwołujących się (istotne dla dodatków)
  • Global może być również używany do pól Public w standardowych modułach, ale jest nielegalny w modułach klasowych i jest i tak nieaktualny - zamiast tego preferuj modyfikator Public . Ten modyfikator również nie jest legalny w przypadku procedur.

Modyfikatory dostępu mają zastosowanie zarówno do zmiennych, jak i procedur.

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

Opcja Moduł prywatny

Bez parametrów Public Sub procedury standardowe moduły są eksponowane jako makra i może być dołączony do kontroli i skrótów klawiaturowych w dokumencie gospodarza.

I odwrotnie, publiczne procedury Function w standardowych modułach są ujawniane jako funkcje zdefiniowane przez użytkownika (UDF) w aplikacji hosta.

Określenie Option Private Module na górze standardowego modułu zapobiega ujawnieniu jego elementów jako makr i UDF do aplikacji hosta.

Wpisz wskazówki

Wskazówki typu są mocno odradzane. Istnieją i zostały tutaj udokumentowane ze względów historycznych i kompatybilności wstecznej. Zamiast tego należy użyć składni 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

Podpowiedzi do czcionek znacznie zmniejszają czytelność kodu i zachęcają do starszej notacji węgierskiej, co również utrudnia czytelność:

Dim strFile$
Dim iFile%

Zamiast tego zadeklaruj zmienne bliżej ich użycia i nazwij rzeczy, których używają, a nie po ich typie:

Dim path As String
Dim handle As Integer

Podpowiedzi typu mogą być również używane na literałach, aby wymusić określony typ. Domyślnie literał liczbowy mniejszy niż 32 768 będzie interpretowany jako literał Integer , ale za pomocą podpowiedzi typu możesz kontrolować, że:

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

Wskazówki dotyczące typów zwykle nie są potrzebne na literałach, ponieważ byłyby przypisane do zmiennej zadeklarowanej za pomocą jawnego typu lub domyślnie przekonwertowane na odpowiedni typ po przekazaniu jako parametry. Konwersji niejawnych można uniknąć za pomocą jednej z jawnych funkcji konwersji typu:

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

Wbudowane funkcje zwracające ciąg znaków

Większość wbudowanych funkcji obsługujących ciągi występuje w dwóch wersjach: wersja z luźnym typem, która zwraca Variant , oraz wersja z silnym typem (kończąca się na $ ), która zwraca String . O ile nie przypisujesz wartości zwracanej do Variant , powinieneś preferować wersję, która zwraca String - w przeciwnym razie istnieje domyślna konwersja wartości zwracanej.

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

Te funkcje to:

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

Zauważ, że są to aliasy funkcji, a nie do końca podpowiedzi . Funkcja Left odpowiada ukrytej funkcji B_Var_Left , a wersja Left$ odpowiada ukrytej funkcji B_Str_Left .

W bardzo wczesnych wersjach VBA znak $ nie jest znakiem dozwolonym, a nazwa funkcji musiała być ujęta w nawiasy kwadratowe. W programie Word Basic było wiele, wiele innych funkcji, które zwracały ciągi zakończone na $.

Deklarowanie ciągów o stałej długości

W VBA ciągi znaków mogą być deklarowane o określonej długości; są one automatycznie wypełniane lub obcinane, aby zachować zadeklarowaną długość.

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

Kiedy stosować zmienną statyczną

Zmienna statyczna zadeklarowana lokalnie nie jest niszczona i nie traci swojej wartości po wyjściu z procedury Sub. Kolejne wywołania procedury nie wymagają ponownej inicjalizacji ani przypisania, chociaż możesz chcieć zerować dowolne zapamiętane wartości.

Są one szczególnie przydatne, gdy późno wiąże się obiekt w podpowłoce pomocniczej, który jest wywoływany wielokrotnie.

Snippet 1: Ponownie użyj obiektu Scripting.Dictionary w wielu arkuszach

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

Snippet 2: Utwórz arkusz roboczy UDF, który późno wiąże obiekt VBScript.RegExp

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
Przykład UDF z obiektem statycznym wypełnionym przez pół miliona wierszy

* Upłynęło czasu, aby wypełnić 500 000 wierszy UDF:
- z Dim rgx As Object : 148,74 sekundy
- z statycznym rgx jako obiektem : 26,07 sekundy
* Należy to wziąć pod uwagę wyłącznie dla porównania względnego. Twoje wyniki będą się różnić w zależności od złożoności i
zakres wykonanych operacji.

Pamiętaj, że UDF nie jest obliczany raz w życiu skoroszytu. Nawet nielotna funkcja UDF przeliczy ponownie, ilekroć wartości w zakresie (zakresach), do których się ona odnosi, mogą ulec zmianie. Każde kolejne zdarzenie ponownego obliczenia tylko zwiększa korzyści ze statystycznie zadeklarowanej zmiennej.

  • Zmienna statyczna jest dostępna przez cały okres istnienia modułu, a nie procedurę lub funkcję, w której została zadeklarowana i przypisana.
  • Zmienne statyczne można deklarować tylko lokalnie.
  • Zmienna statyczna przechowuje wiele takich samych właściwości zmiennej poziomu prywatnego, ale z bardziej ograniczonym zakresem.

Odsyłacze pokrewne: Statyczny (Visual Basic)



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow