VBA
Deklarowanie zmiennych
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ęzykachstatic
służy do tego, aby element klasy (pole, właściwość, metoda, ...) należał do typu, a nie do instancji . Kod w kontekściestatic
nie może odwoływać się do kodu w kontekście instancji . Słowo kluczowe VBAStatic
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ólPublic
w standardowych modułach, ale jest nielegalny w modułach klasowych i jest i tak nieaktualny - zamiast tego preferuj modyfikatorPublic
. 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
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)