Поиск…


Неявная и явная декларация

Если модуль кода не содержит Option Explicit в верхней части модуля, тогда компилятор автоматически (то есть «неявно») создает переменные для вас, когда вы их используете. Они будут использовать переменную типа Variant .

Public Sub ExampleDeclaration()    

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

End Sub

В приведенном выше коде, если указан параметр Option Explicit , код будет прерываться, потому что ему не нужны необходимые инструкции Dim для someVariable и someOtherVariable .

Option Explicit

Public Sub ExampleDeclaration()   

    Dim someVariable As Long 
    someVariable = 10

    Dim someOtherVariable As String
    someOtherVariable = "Hello World"

End Sub

Рекомендуется использовать Option Explicit в модулях кода, чтобы гарантировать, что вы объявите все переменные.

См. VBA Best Practices, как установить этот параметр по умолчанию.

переменные

Объем

Переменная может быть объявлена ​​(при увеличении уровня видимости):

  • На уровне процедуры, используя ключевое слово Dim в любой процедуре; локальная переменная .
  • На уровне модуля, используя ключевое слово Private в модуле любого типа; частное поле .
  • На уровне экземпляра используйте ключевое слово Friend в модуле любого типа; поле друга .
  • На уровне экземпляра, используя ключевое слово Public в модуле класса любого типа; публичное поле .
  • Глобально, используя ключевое слово Public в стандартном модуле ; глобальная переменная .

Переменные всегда должны быть объявлены с наименьшей возможной областью: предпочитайте передавать параметры процедурам, а не объявлять глобальные переменные.

Дополнительную информацию см. В разделе Модификаторы доступа .


Местные переменные

Используйте ключевое слово Dim чтобы объявить локальную переменную :

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

Параметр [As Type] синтаксиса объявления является необязательным. Когда указано, он устанавливает тип данных переменной, который определяет, сколько памяти будет выделено этой переменной. Это объявляет переменную String :

Dim identifierName As String

Если тип не указан, тип неявно Variant :

Dim identifierName 'As Variant is implicit

Синтаксис VBA также поддерживает объявление нескольких переменных в одном выражении:

Dim someString As String, someVariant, someValue As Long

Обратите внимание, что [As Type] должен быть указан для каждой переменной (кроме «Variant»). Это относительно распространенная ловушка:

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

Статические переменные

Локальные переменные также могут быть Static . В VBA ключевое слово Static используется для того, чтобы переменная «запомнила» значение, которое она имела, в последний раз, когда была вызвана процедура:

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

Здесь коллекция values объявляется как Static локальная; потому что это переменная объекта , она инициализируется Nothing . Условие, следующее за объявлением, проверяет, была ли ссылка на объект Set раньше - если она выполняется в первый раз, процедура инициализируется. DoSomethingElse может добавлять или удалять элементы, и они все равно будут в коллекции в следующий раз, когда вызывается DoSomething .

альтернатива

Ключевое слово VBA Static легко может быть неправильно понято - особенно опытные программисты, которые обычно работают на других языках. На многих языках static используется для того, чтобы член класса (field, property, method, ...) принадлежал типу, а не экземпляру . Код в static контексте не может ссылаться на код в контексте экземпляра . Ключевое слово VBA Static означает что-то совершенно другое.

Часто Static локальный объект может быть также реализован как Private переменная (поле) на уровне модуля, однако это бросает вызов принципу, с помощью которого переменная должна быть объявлена ​​с наименьшей возможной областью; доверяйте своим инстинктам, используйте то, что вы предпочитаете - оба будут работать ... но использование Static без понимания того, что он делает, может привести к интересным ошибкам.


Дим против частного

Ключевое слово Dim является законным на уровне процедур и модулей; его использование на уровне модуля эквивалентно использованию ключевого слова Private :

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

Ключевое слово Private доступно только на уровне модуля; это вызывает резервирование Dim для локальных переменных и объявление переменных модуля с помощью Private , особенно с контрастным ключевым словом Public которое должно быть использовано для объявления публичного участника. Также можно использовать Dim везде - то , что имеет значение консистенция:

«Частные поля»

  • DO использовать Private чтобы объявить переменную уровня модуля.
  • DO используйте Dim чтобы объявить локальную переменную.
  • НЕ используйте Dim чтобы объявить переменную уровня модуля.

«Тусклый везде»

  • DO используйте Dim чтобы объявить что-либо частным / местным.
  • НЕ используйте Private чтобы объявить переменную уровня модуля.
  • ИЗБЕГАЙТЕ объявление Public полей. *

* В общем, следует избегать объявления Public или Global полей.


поля

Переменная, объявленная на уровне модуля, в разделе объявлений в верхней части тела модуля является полем . Public поле, объявленное в стандартном модуле, является глобальной переменной :

Public PublicField As Long

Доступ к переменной с глобальной областью можно получить из любого места, включая другие проекты VBA, которые будут ссылаться на проект, в котором он объявлен.

Чтобы сделать переменную global / public, но только видимую изнутри проекта, используйте модификатор Friend :

Friend FriendField As Long

Это особенно полезно в надстройках, где намерение заключается в том, что другие проекты VBA ссылаются на проект надстройки и могут потреблять открытый API.

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

Поля друзей недоступны в стандартных модулях.


Поля экземпляра

Переменная, объявленная на уровне модуля, в разделе объявлений в верхней части тела модуля класса (включая ThisWorkbook , ThisDocument , Worksheet , UserForm и модулях классов ) является полем экземпляра : оно существует только до тех пор, пока существует экземпляр класс вокруг.

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

Инкапсулирующие поля

Данные Instance часто хранится Private и дублирован инкапсулируются. Закрытое поле можно открыть с помощью процедуры Property . Чтобы публично публиковать приватную переменную, не предоставляя доступ к записи вызывающему, модуль класса (или стандартный модуль) реализует элемент « 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

Сам класс может изменить инкапсулированное значение, но вызывающий код может получить доступ только к Public членам (и членам Friend , если вызывающий объект находится в одном проекте).

Чтобы разрешить вызывающему абоненту:

  • Инкапсулированное значение , модуль предоставляет элемент Property Let .
  • Ссылка на инкапсулированные объекты , модуль предоставляет член Property Set .

Константы (Const)

Если у вас есть значение, которое никогда не изменяется в вашем приложении, вы можете определить именованную константу и использовать ее вместо буквенного значения.

Вы можете использовать Const только на уровне модуля или процедуры. Это означает, что контекст объявления для переменной должен быть классом, структурой, модулем, процедурой или блоком и не может быть исходным файлом, пространством имен или интерфейсом.

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

Хотя можно считать хорошей практикой указывать константные типы, это строго не требуется. Не указывая тип, он все равно приведет к правильному типу:

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

Обратите внимание, что это специфично для констант и в отличие от переменных, где не указано, что тип приводит к типу Variant.

Хотя можно явно объявить константу как String, невозможно объявить константу в виде строки с использованием синтаксиса строки фиксированной ширины

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

Модификаторы доступа

Dim должна быть зарезервирована для локальных переменных. На уровне модуля предпочитайте явные модификаторы доступа:

  • Private для частных полей, доступ к которым возможен только в том модуле, в котором они объявлены.
  • Public для общедоступных полей и глобальных переменных, к которым может обращаться любой вызывающий код.
  • Friend для переменных, публикуемых в рамках проекта, но недоступных для других проектов VBA, связанных с надстройками (для надстроек)
  • Global также может использоваться для Public полей в стандартных модулях, но является незаконным в модулях классов и в любом случае является устаревшим - вместо этого предпочитайте Public модификатор. Этот модификатор также не является законным для процедур.

Модификаторы доступа применимы как к переменным, так и к процедурам.

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

Дополнительный модуль

Открытые Sub процедуры в стандартных модулях отображаются как макросы и могут быть прикреплены к элементам управления и сочетания клавиш в документе хоста.

И наоборот, публичные процедуры Function в стандартных модулях отображаются как пользовательские функции (UDF) в хост-приложении.

Указание отдельного модуля Option Private Module в верхней части стандартного модуля не позволяет его членам отображаться как макросы и UDF для приложения-хозяина.

Тип подсказки

Тип подсказки сильно обескуражен. Они существуют и документируются здесь по причинам исторической и обратной совместимости. As [DataType] этого следует использовать синтаксис 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

Типовые подсказки значительно уменьшают читаемость кода и поощряют венгерскую нотацию, которая также препятствует читаемости:

Dim strFile$
Dim iFile%

Вместо этого, объявляйте переменные ближе к их использованию и называйте вещи тем, что они используются, а не после их типа:

Dim path As String
Dim handle As Integer

Типовые подсказки также могут использоваться в литералах, чтобы обеспечить соблюдение определенного типа. По умолчанию числовой литерал, меньший, чем 32 768, будет интерпретироваться как литерал Integer , но с подсказкой типа вы можете контролировать это:

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

Типные подсказки обычно не нужны для литералов, потому что они будут назначены переменной, объявленной с явным типом, или неявно преобразуются в соответствующий тип при передаче в качестве параметров. Неявные преобразования можно избежать, используя одну из явных функций преобразования типов:

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

Строковые возвращаемые встроенные функции

Большинство встроенных функций, которые обрабатывают строки, представлены в двух версиях: свободно напечатанная версия, которая возвращает Variant , и строго типизированную версию (заканчивающуюся на $ ), которая возвращает String . Если вы не назначаете возвращаемое значение для Variant , вы должны предпочесть версию, которая возвращает String противном случае происходит неявное преобразование возвращаемого значения.

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

Эти функции:

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

Обратите внимание, что это псевдонимы функций, не совсем намеки на тип . Функция Left соответствует скрытой функции B_Var_Left , а версия Left$ соответствует скрытой функции B_Str_Left .

В ранних версиях VBA знак $ не является допустимым символом, а имя функции должно быть заключено в квадратные скобки. В Word Basic было много и много функций, которые возвращали строки, которые заканчивались в $.

Объявление строк фиксированной длины

В VBA строки могут быть объявлены с определенной длиной; они автоматически дополняются или усекаются, чтобы поддерживать указанную длину.

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

Когда использовать статическую переменную

Статическая переменная, объявленная локально, не разрушается и не теряет своего значения при выходе из процедуры Sub. Последующие вызовы процедуры не требуют повторной инициализации или присвоения, хотя вы можете «нулевать» любые запоминаемые значения.

Они особенно полезны при позднем связывании объекта в вспомогательном подэлементе, который вызывается повторно.

Фрагмент 1: повторное использование объекта Scripting.Dictionary на многих листах

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: создать рабочий лист UDF, который опоздает с привязкой к объекту 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
Пример UDF со статическим объектом, заполненным полмиллиона строк

* Истекшее время, чтобы заполнить 500K строк с помощью UDF:
- с Dim rgx As Object : 148.74 секунд
- с Static rgx As Object : 26.07 секунд
* Они должны учитываться только для относительного сравнения. Ваши собственные результаты будут варьироваться в зависимости от сложности и
объем выполненных операций.

Помните, что UDF не рассчитывается один раз в жизни книги. Даже энергонезависимый UDF будет пересчитываться всякий раз, когда значения в пределах диапазона (ов), которые он ссылается, могут быть изменены. Каждое последующее событие пересчета только увеличивает преимущества статически объявленной переменной.

  • Статическая переменная доступна для времени жизни модуля, а не для процедуры или функции, в которой она была объявлена ​​и назначена.
  • Статические переменные могут быть объявлены только локально.
  • Статическая переменная содержит много одинаковых свойств переменной уровня частного модуля, но с более ограниченной областью.

Ссылки по теме: Static (Visual Basic)



Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow